Lakshya

Security Engineering & Tooling · Chapter 1 of 8

What the tools are, and what they structurally cannot do

Security tooling is sold on what it finds. The useful question is what each category is blind to by construction.

9 min read2 diagramsAll 8 chapters

Every security tool has a shape, and the shape decides what it can never see. That is not a maturity problem that a better model fixes — it follows from where the tool sits. An interview is largely testing whether you know the boundaries.

SAST — static analysis of source

Genuinely detects: syntactic and dataflow-reachable defects where source and sink are both in the code it can see — injection (SQL, command, log), server-rendered XSS, hardcoded crypto misuse, unsafe deserialisation entry points, path traversal. Modern engines follow taint across function and file boundaries within one repository.

Structurally cannot detect: authorisation and access-control logic, business-logic flaws, anything whose correctness depends on runtime configuration, and anything crossing a service boundary. There is no syntactic signature for “this endpoint should have checked tenant ownership” — which is why broken object-level authorisation, consistently among the most damaging real-world web flaws, is still a manual-testing problem. A tool cannot know your intended authorisation model unless you tell it.

The false-positive problem is the adoption decision, not a footnote.

The mechanism: developers receive findings they judge to be wrong, learn the tool is unreliable, and then ignore true positives at the same rate as false ones. Recovery is very hard once that trust is gone.

Do not quote a single number. Published rates range from about 20% to over 90% depending on language, ruleset and codebase — a 2025 study reports ~79% on a standard benchmark corpus and up to 38% in real-world multi-language cases; a Python analysis found 99.5% of flagged command injections were false. Java and C/C++ do better than Python and JavaScript, because static types give the analyser more to work with.

The “NIST found 78% false positives for Java” line is folklore. It is cited everywhere and traces to no specific NIST publication. Do not attribute it.

What actually changed the category: the move from pattern and AST matching to interprocedural taint analysis. “Flag eval()” produces noise; “flag eval() reachable from an HTTP parameter without passing a sanitiser” produces far less. That line is also the commercial dividing line — it is what most vendors put behind the paid engine.

SCA, and the reachability shift

The old model: build an SBOM, match against a CVE database, report “you have 4,312 vulnerabilities.” Technically accurate, operationally useless. It generates a backlog nobody can work, ranked by a score that measures theoretical severity in the abstract rather than risk in your application.

THE SINGLE MOST IMPORTANT NUMBER IN VULNERABILITY MANAGEMENT ~6% of all published CVEs have EVER been observed exploited in the wild Cyentia Institute / FIRST: 13,807 of 237,687 CVEs as of 31 May 2024. The grey bar is every CVE ever published. AND THE PROPORTION THAT MATTERS IS FALLING 2H 2023 KEV:CVE2.7%1H 2026 KEV:CVE1.4%CVE volume, half on half+45%KEV volume, half on half+10% VulnCheck, State of Exploitation 1H-2026. CVE issuance is growing far faster than exploitation. BUT EXPLOITATION IS GETTING FASTER, NOT SLOWER Median CVE-publication to KEV-listing fell from 120 days in 2025 to 80 days in 1H 2026. 23.4% of KEVs showed exploitation ON OR BEFORE the CVE publication date. Rarer, but faster — which argues for prioritisation, not for scanning more.
This is the number to lead with when asked how you prioritise. CVSS was never a risk score, and the base rate is what proves it.

The one prioritisation result with real evidence behind it is EPSS — the Exploit Prediction Scoring System, governed by FIRST. At a threshold of 0.088, version 3 gives roughly 82% coverage of exploited vulnerabilities for 7.3% of the remediation effort, against a CVSS-based strategy at 69.9% coverage and 18.5% efficiency — about double the coverage at triple the efficiency. Be precise about what that proves: it is a prediction-quality result. Nobody has shown that EPSS-driven patching reduces incidents.

THREE DIFFERENT THINGS ARE SOLD AS ONE WORD 1 · DEPENDENCY-LEVELIs this package imported anywhere at all?Cheap. Kills only unused-dependency noise — coarse.2 · FUNCTION-LEVEL (static)Does a call path exist from my code to the vulnerable function?Needs a SUCCESSFUL BUILD and a whole-program call graph.3 · RUNTIMEWas the vulnerable code actually loaded in production?Needs an agent. Highest confidence, narrowest coverage. THE OUTPUT IS TERNARY REACHABLEUNREACHABLEPOTENTIALLY REACHABLE The third bucket means “the analysis could not determine it” — dynamic languages, reflection, unsupported package managers. Vendors quote the reduction, not this bucket’s size. AND REACHABILITY IS NOT A SAFETY PROOF It answers “can this be called?” — not “can an attacker control the input to it?” A reachable function on fully trusted input is still not exploitable. An unreachable one becomes reachable next sprint, and nothing re-opens the ticket. Treat it as a triage prior. Treating “unreachable” as “closed” is this discipline’s new way to miss things.
Conflating these three is a common interview failure. “We do reachability” means very different things at each level, and the third output bucket is the one nobody quotes.

Where static reachability loses precision: reflection, dynamic dispatch, dependency injection, eval-style loading, native and foreign-function calls, and service boundaries. Dynamic languages are materially worse than statically typed ones.

Vendor reachability numbers — do not repeat these as fact

“Filters ~92% of false positives.” “Up to 95%.” “Up to 80% reduction.” All three are vendor marketing: self-measured, no stated baseline, no independent replication.

There is no independent academic or third-party evaluation of commercial reachability precision and recall that I could find. Academic call-graph research reports improvements in the 8–84% range on precision/recall — for research call-graph construction, which is not a validation of any product.

The question that separates a serious answer from a repeated one: reduction against what baseline, and what did it do to the true positives?

Vulnerable, malicious, and legally risky are three different things

The interview-grade distinction. A vulnerable dependency and a malicious dependency are different threat models needing different detection. CVE matching cannot find a typosquatted package published yesterday, because there is no CVE for it — only behavioural analysis of what the package does at install time (network access, filesystem reach, obfuscation, install scripts) will. The npm worm attacks are why this split now matters, and it is the entire reason a vendor like Socket exists alongside the CVE scanners.

And there is a third category that a security-shaped tool will never report, because nothing is broken. Every dependency arrives under a licence. Most are permissive. Some are copyleft — the GPL family — and can require that if you distribute software containing them, you make your own source available. The code works perfectly. There is no vulnerability. The exposure is contractual.

This is what Black Duck was built for, two decades before its vulnerability scanning grew alongside it — and it is why a dependency scan is a standard step in acquisition due diligence. A buyer’s lawyers want to know what is inside the product they are paying for, and a copyleft library deep in a commercial codebase is the kind of finding that moves a price. If someone asks why you would buy Black Duck when you already run a vulnerability scanner, that is the answer. Fuller treatment in the SDLC tooling chapter.

The tools, and one licence story people get wrong

ToolModelWhat it is actually for
SemgrepEngine LGPL 2.1; registry rules under the Semgrep Rules LicenseFast, writable rules. See below — the engine was not closed-sourced
SonarQubeCommunity (LGPL) + commercialOrigin is code quality; security is a later layer. Strong on maintainability, weaker on deep taint
CheckmarxCommercialThe regulated-enterprise incumbent. Heaviest configuration burden. Now also owns ZAP
Snyk CodeCommercial, free tierDeveloper workflow is the product — IDE and PR integration, not the engine
CodeQL / GHASFree for public repos, paid for privateA query language over a code database. Most expressive engine here, steepest learning curve
OpengrepLGPL 2.1 forkForked from Semgrep CE in January 2025 by a competitor coalition, restoring cross-function taint in the open fork
CoverityCommercialDeep static analysis with a C and C++ heritage — safety-critical work, automotive and medical. Slow and thorough rather than fast and conversational
Black DuckCommercialDependencies, including their licences — see above. Same company as Coverity since October 2024, when Synopsys sold its Software Integrity Group for $2.1bn and it took the Black Duck name
FortifyCommercialThe other long-established enterprise scanner, now under OpenText

What actually happened to Semgrep, since it gets told wrong. The engine remains LGPL 2.1. What changed in December 2024 was the rules: the registry moved to a licence limiting use to internal, non-competing, non-SaaS contexts, and “Semgrep OSS” was renamed Community Edition. Individual engineers, consultants and internal corporate use were never restricted — the change was aimed at vendors reselling the rules. If you are an end user, nothing broke.

And a pricing fact worth having straight, because it is a billing trap rather than a licence one: GitHub Advanced Security was split in April 2025 into Secret Protection and Code Security as separate SKUs, and a “committer” is anyone who contributed to an enabled private repo in the last 90 days. A contractor who pushed once in a quarter is a billable committer.

Check yourself

What can SAST never find, however good it gets?Authorisation logic, business-logic flaws, anything depending on runtime config, anything crossing a service boundary. There is no syntactic signature for 'this endpoint should have checked ownership'.
Why do false positives matter more than the miss rate?Because developers who learn the tool is unreliable ignore true positives at the same rate as false ones. It is an adoption failure, not an accuracy one.
What proportion of published CVEs have ever been exploited?About 6% — 13,807 of 237,687 as of May 2024 (Cyentia/FIRST). And the KEV-to-CVE ratio fell to 1.4% in 1H 2026.
What are the three levels of reachability?Dependency (is it imported), function-level static (does a call path exist), runtime (was it actually loaded). Different costs, different precision.
What does 'unreachable' NOT mean?Safe. It answers 'can this be called', not 'can an attacker control the input'. And unreachable code becomes reachable next sprint, with nothing to re-open the ticket.
Name a dependency risk no security scanner will report.A copyleft licence. Nothing is broken and the code works — the exposure is contractual, which is why acquisition due diligence includes a dependency scan, and why Black Duck exists.
Did Semgrep close-source its engine?No. The engine is still LGPL 2.1. The registry rules changed licence in Dec 2024, aimed at vendors reselling them — internal corporate use was never restricted.
← All chaptersTesting what is deployed — DAST, secrets, and the commoditised scanners →