StackAttestTechnical Trust
Vulnerable dependency check

Check whether you are shipping packages with known vulnerabilities

This is the least interesting failure on the site and the cheapest to fix, which is exactly why it ships. Nobody picked these packages one at a time, nobody has read them, and the advisories against them are public by definition, so anyone deciding whether to trust your application can look them up before you have.

Validate a repositoryHow validation worksSee an example Passport

Where the evidence about your dependencies comes from

Reading the repository does nearly all the work on this question, and it is worth saying what the other layers do not do. A public URL scan cannot see a dependency tree at all, so it reports this control as uncovered rather than inferring a version from a response header.

Repository validation

E2
Repository

Reads every dependency manifest in the repository, including the ones sitting in subdirectories of a monorepo, and records whether each has a lockfile beside it. Where the lockfile is in a format it parses, it takes the resolved name and version of every package listed, transitive ones included, because that resolved list is the only thing an advisory database can actually be asked about. A lockfile in a format it does not parse is recorded as present rather than guessed at, and a manifest with no lockfile at all is reported as the finding it is.

Runtime validation

E4
Runtime

Builds and runs the application, so the versions checked are the ones the image installed rather than the ones a file said it would install. That is a stronger fact than reading a lockfile, and the gap between the two is exactly where this class of problem hides: a manifest declares what is acceptable, an install decides what is there.

What actually goes wrong here

None of this is exotic. It is the ordinary way a dependency tree gets away from a small team, and the reason the fix is usually cheap is the same reason it gets postponed.

A whole dependency tree, acquired in one step

One generation step installs a framework, the framework installs what it needs, and those install what they need. What arrives is a dependency tree nobody selected, in a single commit that looks like a single decision. That is not a criticism of the tooling, it is what package managers do. It does mean the question of what you are shipping was never actually put to anyone.

A known vulnerability is a published advisory, not a proven exploit

It means somebody found a weakness in a package, a version range was declared affected, and the finding is now public. It does not mean an attacker can do anything to your application. The advisory is a statement about the package. Whether it is also a statement about you depends on whether your code reaches the affected function, in the way the advisory describes, with input somebody else controls. Both of the easy readings are wrong: treating every advisory as a breach, and treating none of them as one.

Reachability is the real question and almost nothing can answer it

A critical advisory in a parser you never call is a smaller problem than a moderate one sitting on your login path, and a tool that reads a lockfile cannot tell those apart, because a lockfile records what is installed rather than what runs. Working out which advisories reach your code is work a person still does. The honest thing a scan can do is hand you the list, the severity and the fixed version, and be clear that the ordering is yours.

Direct and transitive are different problems with different fixes

A direct dependency is one you asked for and can upgrade. A transitive one arrived because something else wanted it, and usually you cannot move it without moving whatever pulled it in. Most of a tree is transitive, so most advisories land there, and the fix is generally to update the parent rather than the package the advisory names. Pinning a transitive version behind its parent's back does work, and it is a thing you should know you have done rather than something to discover later.

The lockfile is what decides which code actually runs

A manifest says which versions are acceptable. A lockfile says which ones were resolved. Without one, two installs of the same commit can produce different trees, so the answer to what am I running is whatever the last install happened to pick, and nothing can be audited because nothing is fixed. That is why a missing lockfile is a finding of its own rather than untidiness.

Sooner or later an advisory will have no fix

The package is abandoned, or the fix is a major version your application cannot take this month. There is no scanner answer to that. The options are to replace the package, to vendor and patch it, or to write down why the affected path is not reachable from your application and put a date on looking again. The third is a legitimate answer. It is only legitimate written down, because an unwritten one is indistinguishable from having forgotten.

What the result looks like

An illustrative extract, not a real customer result. Every row carries the evidence grade behind it, and a control nobody could establish says so.

ControlStatusEvidenceNote
Dependencies are free of known-critical vulnerabilitiesFailedE3Two resolved versions carry critical advisories, both with a published fix
Injection-safe data accessVerifiedE2Query construction is parameterised in every path read
Secrets are managed outside source codeVerifiedE2No credential material in the source or in git history
Server-side input validation on state-changing endpointsPartialE2Typed schemas on most endpoints, two take a free-form body
Deployment rollback path existsUncoveredNot gradedNothing in the repository or the run establishes one

Mapped to published standards

Each control is tested against a named clause, so a result means something outside our own vocabulary. Mapping is not certification, and none of these bodies endorse StackAttest.

OWASP ASVS 5SLSANIST SSDFCWE

What this check is not

  • It does not establish reachability. A run reports which resolved versions carry known advisories and how severe each one is. Whether an advisory reaches your code is a judgement about your application, so a run that only read the source reports the control as partial rather than claiming a clean bill of health it cannot support.
  • A URL scan cannot answer this question at all. With no dependency manifest to read, the control is reported uncovered rather than passed, on this page and in the product.
  • It is not a penetration test. A deterministic check and a runtime probe are not an adversarial human engagement, and there are classes of weakness only a person hunting for them will find.
  • It is not SOC 2 and does not replace it. SOC 2 attests to organisational controls over time; this validates technical controls in the software. They answer different questions for different buyers.
  • It does not replace human due diligence. It gives a reviewer repeatable evidence to start from, which is a different thing from being the reviewer.
  • Controls the run could not reach are reported as uncovered rather than passed. A result you did not earn is worse than no result.

Questions

How do I check for vulnerable dependencies?

Commit a lockfile, then check the versions resolved in it against a public advisory database. Your package manager already does this: npm audit, pip-audit and their equivalents are free, fast and the right first move. What they hand back is a list rather than a priority order, because the ordering depends on which advisories your code actually reaches, and that part is yours.

Does a critical advisory mean my app is exploitable?

No. It means a public advisory names a version range you are running. Whether it touches you depends on whether your code calls the affected path, in the way described, with input somebody else controls. A critical advisory in a package you never call is a smaller risk than a moderate one on your auth path, and nothing that reads a lockfile can tell you which of those you have.

What if there is no fix available?

Replace the package, vendor and patch it, or write down why the affected path is not reachable from your application and set a date to look at it again. The third option is legitimate, and it is only legitimate written down. An undocumented decision to accept a risk is the same artefact as having missed it.

Do I really need a lockfile?

Yes, and it is the highest-value item on this page. Without one, two installs of the same commit can resolve different versions, so nothing about what you run is fixed and nothing about it can be audited. A manifest with no lockfile beside it is reported as a finding in its own right, before any advisory is looked up.

What does StackAttest do here exactly?

Repository validation reads every dependency manifest in the repository and records whether each has a lockfile. Where that lockfile is in a format it parses, it takes the resolved name and version of every package listed, transitive ones included, and those public coordinates, a package name, its ecosystem and its version and nothing else, are what an advisory check needs. No source and no private package contents go with them. Where that check runs, its result settles the control called dependencies are free of known-critical vulnerabilities, at the strength of the evidence behind it: reading a lockfile proves what is pinned, not that the pinned versions are clean, so a source-only run reports partial rather than verified.

Is this different from what my package manager already tells me?

Not in kind. It reads the same public advisories. The difference is that a validation run puts the result next to the other controls, records how strong the evidence behind it is, and reports the control as uncovered when it had no manifest to read, rather than letting a green terminal stand for the whole question. Run the local audit as well. It is free and it is faster.

Related

Free AI app security checkWebhook security auditAI code auditCursor security auditProduction readiness auditVibe code audit

Find out what is actually true of your application

Start with the layer you can run today. The report says which layers ran and what they could not reach, so the result is honest about its own limits.

Validate a repositoryHow validation works