Application Security

What is application security?

Application security covers first-party code, open-source dependencies, secrets and the build pipeline. Exposure management adds one question to all of it: which weaknesses can actually be reached.
Backed by:

Key takeaways

Application security is the practice of finding and fixing weaknesses in software - in first-party code, in the open-source dependencies that code pulls in, and in how the application is built, configured and deployed. Treated as part of exposure management, it adds a second question to every finding: whether the weak code is reachable and exploitable in the application as it actually runs.

  • Finding volume is not risk. Most findings from code and dependency scanners are not exploitable in the application as deployed, so a raw count says little about exposure.
  • The tool categories answer different questions. Static analysis inspects source, dynamic testing probes a running instance, composition analysis inventories dependencies, and posture management aggregates the rest.
  • Reachability separates a finding from an exposure. Package presence, the vulnerable function being called, and attacker-controlled data arriving at it are three distinct claims.
  • Dependency fixes are graph problems. A single version bump can break packages pinned or compiled against the previous release, so the safe unit of change is often a coordinated set.
  • Precision decides whether the queue gets worked. When most of what reaches an engineer is real, the queue is worked. When it is not, all of it is discounted, including the findings that matter.

01 - Why does it matter?

Application security has a credibility problem earned by arithmetic. Static analysis and dependency scanning produce finding counts in the thousands, of which a small minority are exploitable as deployed. Developers learn that the queue is mostly noise and discount all of it, including the findings that would have mattered. Adding scanners makes that worse; precision is the only intervention that changes the dynamic.

The second problem is the shape of the request. A finding hands an engineer an investigation rather than a change: which version resolves it, whether that version breaks anything else, and when there is a window to test it. Answering those is the real cost, and since discovery capacity has risen faster than engineering capacity, filtering by exploitability is what keeps the actionable set finite.

  • Findings are not exposures. Composition analysis flags a library, not a reachable path, and most flagged libraries are never called in a way that matters.
  • Severity is a weak proxy. A base CVSS score describes a vulnerability in the abstract, not the configuration it landed in.
  • Code ownership is often unrecorded. Version control history and CODEOWNERS files are better evidence than an inventory field, and many repositories carry neither.
  • Secrets outlive the commit that introduced them. A credential deleted in a later commit stays in history and stays valid until rotated.

02 - What application security covers

The practice spans four surfaces. First-party code carries logic flaws, injection paths and broken authorisation. Dependencies carry vulnerabilities disclosed after the code was written, which is why dependency risk changes without anyone touching the repository. The build pipeline carries build credentials, package registries and signing keys. Runtime configuration - permissions, exposed ports, default credentials, debug endpoints left enabled - is where an otherwise sound application becomes reachable.

03 - The tool categories, briefly

  • SAST, static application security testing. Analyses source or compiled code without running it. Broad coverage, historically high false-positive rates because it cannot observe runtime behaviour.
  • DAST, dynamic application security testing. Probes a running application from outside. Fewer false positives, narrower coverage, and it sees only the paths the test exercises.
  • SCA, software composition analysis. Inventories third-party dependencies and matches them against known vulnerability data, producing the largest raw finding counts.
  • Secrets detection. Scans source, history and build logs for credentials and keys. Detection is easy; rotation is the fix.
  • Reachability analysis. Determines whether a flagged vulnerability is invocable in the application as assembled, turning a finding into an exposure or removing it from the set.
  • ASPM, application security posture management. Aggregates output from the categories above, correlates it to applications and owners, and manages policy.

04 - How a dependency enters an application

Every route has a different fix mechanic. A manifest edit resolves a direct dependency, a rebuild resolves a base image, and vendored source has to be patched by hand because no version number points at a replacement.

  • Direct dependencies. Declared in the manifest by a developer who chose them. The smallest part of a resolved tree and the easiest part to change.
  • Transitive dependencies. Pulled in by the direct ones, usually the large majority of a resolved tree. Nobody selected them, and the upgrade decision often belongs to an upstream maintainer rather than to the team holding the finding.
  • Vendored or copied source. Third-party code committed into the repository rather than resolved by a package manager. It carries no version metadata, so composition analysis frequently cannot see it at all.
  • Operating-system packages in a base image. A container inherits the package set of the layer it is built on. The fix is a rebuild from an updated base, not a change to application code.
  • Bundled and minified assets. Front-end build steps inline third-party code into a single shipped artefact that no longer names the versions it was assembled from.
  • Build-time and pipeline dependencies. Compilers, build plugins, test harnesses and continuous-integration actions run with repository credentials. They are dependencies of the pipeline rather than of the application, and rarely appear in the same inventory.

05 - Reachability and the difference between a finding and an exposure

Composition analysis answers a presence question: is a vulnerable version of this package in the dependency tree. Function-level reachability asks whether the vulnerable function is called at all, directly or transitively. Data-flow or taint analysis asks whether data an attacker can influence arrives at the vulnerable parameter. A function invoked only with trusted internal constants is a materially different risk from the same function at the end of a path beginning with an untrusted request.

The technique has real limits. Reflection, dynamic dispatch and configuration-driven loading degrade call-graph fidelity, forcing an analysis either to over-approximate, which reintroduces noise, or to under-approximate, which hides exposure. Runtime-observed reachability inherits the opposite limit: a path production traffic has never exercised looks unreachable until the day it is exercised.

06 - A worked example: present, loaded, and never callable

CVE-2021-44228 in Apache Log4j 2, disclosed in December 2021, is the clearest illustration available. Enormous numbers of Java applications had a vulnerable Log4j version in the build manifest, usually pulled in transitively rather than chosen. Presence was near-universal and presence was the wrong measure. An application that bound a different logging implementation, or never routed untrusted input into a logged message, contained the vulnerable class without entering the lookup path that made it exploitable: loaded, zero exposure. An application logging a request header on an internet-facing endpoint was fully exposed by the identical version, and the manifest cannot tell the two apart.

The fix side has the same shape. Upgrading NumPy to 2.0 is an ABI break that fails builds of pandas, SciPy and scikit-learn compiled against 1.x: a bot proposes the bump, package-level checks pass, and the application dies at import.

07 - A worked example: a secret that outlives its commit

An engineer commits a configuration file containing a long-lived cloud access key, notices within a day, and removes it in a follow-up commit. The file is gone from the working tree, the removal is merged, and the finding is marked resolved.

The credential is still present and still valid. The earlier blob remains in the object database, and every clone taken before the removal keeps a copy: forks, continuous-integration caches, build artefacts, developer working copies. Rewriting history removes the object from the canonical repository and does nothing about the copies already distributed.

The change that closes the exposure is rotation: issue a replacement credential, update the systems that consume it, revoke the original, and read the provider's access logs for use of the old key between commit and revocation. That last step is the one most often skipped, and it separates a rotated secret from one that had already been used. Deletion edits the code; rotation moves the risk.

08 - How to evaluate an application security approach

  • Ask which reachability question is answered. Package presence, call-graph reachability and attacker-controlled data flow are three claims, and only the third describes exploitability.
  • Ask how indirection is handled. Reflection and configuration-driven loading are where call graphs lose fidelity, and a documented approximation is more credible than a claim of complete coverage.
  • Check whether a fix arrives as a change. A proposed version set, a pull request into the existing pipeline and a rollback path are actionable; a ticket requesting investigation moves work, not risk.
  • Measure fix rate, not finding rate. Time from finding to merged change, and the share of findings that ever reach a merge, describe the programme. Open counts describe the scanner.

09 - Common misconceptions

  • A vulnerable dependency in the manifest means the application is vulnerable. Presence is necessary, not sufficient. The code has to be callable, and for most flaw classes attacker-influenced data has to reach it.
  • A high CVSS score means fix it first. Base scores describe intrinsic severity without environmental context. Exploit prediction and known-exploited status order a queue better.
  • Static and dynamic analysis are alternatives. They fail in opposite directions: static over-reports because it cannot see runtime state, dynamic under-reports because it only sees exercised paths.
  • An SBOM is a security control. An SBOM is an inventory. It shortens the time to answer whether a new vulnerability affects anything shipped, and says nothing about exploitability.
  • Reachable means exploitable. Reachability narrows the candidate set; it does not demonstrate that an attack succeeds. Input validation, memory protections and a mitigating configuration can leave a reachable function unexploitable, which is why reachability and validation answer different questions.
  • Fixing the direct dependency fixes the tree. Most vulnerable packages arrive transitively. Bumping a direct dependency helps only if its newer release resolves the transitive one; otherwise the available moves are an override, a pin, or waiting on the intermediate maintainer.

10 - Standards and sources

Vulnerability identifiers come from the CVE Program, operated by MITRE with CISA sponsorship. Severity scoring uses CVSS and exploitation likelihood uses EPSS, both maintained by FIRST, and CISA publishes the Known Exploited Vulnerabilities catalogue of confirmed in-the-wild exploitation. Dependency inventories are expressed as an SBOM in CycloneDX or SPDX, the latter standardised as ISO/IEC 5962. OWASP publishes the Top 10 and the Application Security Verification Standard, and NIST SP 800-218 describes secure development practices.

Frequently Asked Questions

Does reachability analysis replace static and composition analysis? No. It is a filter applied to their output. Scanners establish that a weakness exists in code or in a dependency; reachability establishes whether that code can be invoked and whether untrusted data can arrive at it.

How does function-level reachability differ from what composition analysis reports? Composition analysis reports that a vulnerable package version is in the dependency tree. Function-level reachability reports whether the vulnerable function is invoked, and data-flow analysis whether untrusted input can reach it. The first is a presence check; the others are exploitability checks.

Will an automated dependency upgrade break the build? It can, which is why the safe unit of change is often a coordinated upgrade set. Impact analysis across the dependency graph identifies consumers that would break, and where no safe path exists the finding is better staged with the analysis attached.

Where does secrets scanning fit? It is a separate surface covering credentials in source, history and build output, where the fix is rotation rather than deletion.

Why are so many application security findings not exploitable? Because the common scanners answer a presence question rather than an exploitability one. Composition analysis reports that a vulnerable package version resolved into the build; static analysis reports a pattern in source it cannot observe running. Whether the code is invoked, whether attacker-influenced data reaches it, and whether the configuration enables the affected feature are three further conditions, each of which removes findings from the set.

Sources

  • Verizon, 2026 Data Breach Investigations Report.
  • MITRE, CVE Program identifier and CNA documentation, 2026.
  • FIRST, Common Vulnerability Scoring System v4.0 specification, 2023.
  • FIRST, Exploit Prediction Scoring System model documentation, 2025.
  • CISA, Known Exploited Vulnerabilities Catalog, 2026.
  • NIST, Secure Software Development Framework, SP 800-218, 2022.