Most security training still teaches engineers to worry about the code they write. Soroosh Khodami's argument is that the more dangerous surface is the code they merely install — and that the industry has not meaningfully improved since Log4Shell. He opens by asking the room whether we are ready for the next crisis of that scale and answers his own question immediately: based on his experience across different companies and clients, we are not. The talk then spends its first act proving that claim with live demonstrations rather than statistics.
Khodami is a solution architect at Code Nomads, a consultancy in Amsterdam, currently working with Rabobank on platforms that help delivery squads reduce exactly this class of risk. He describes himself as a developer since the dial-up days, and says his examples come from research and hands-on architecture work at that client. This 51-minute, 51-second talk was recorded at InfoQ Dev Summit Munich and published by InfoQ on March 30, 2026.
These notes report what Khodami presented and explicitly mark the small amount of background context added for readers unfamiliar with the tooling.
What You Will Learn
- How a reverse shell works, and why an outbound connection defeats a firewall that blocks every inbound one.
- How dependency confusion and a compromised build environment turn a routine
mvn installornpm installinto remote code execution. - Why transitive dependencies mean a "Hello World" service carries dozens of independent attack surfaces.
- How generative AI raises the hit rate of typosquatted package names.
- A tiered, practical set of controls — critical, essential, and advanced — with the rough effort each one costs.
- What a Software Bill of Materials contains, how to generate one, and why storing and monitoring SBOMs centrally is what converts a year-long Log4Shell response into an hour-long one.
- Why severity and priority are different, and how EPSS and deployment context drive real remediation order.
Act I: Three Demonstrations
The Reverse Shell
Khodami starts with a question the audience cannot honestly dodge: who has ever copied a block of bash commands from a highly upvoted forum answer, or from ChatGPT or Claude, and run it? Developers say they would never do this blindly. Attackers, he says, find that claim funny — all of us are one command away from gifting access to a hacker.
The mechanism is a reverse shell. In a normal SSH session you initiate a connection to a server and type commands there. A reverse shell inverts the direction: the victim's machine initiates an outbound connection to the attacker's machine and attaches a shell to it, so the attacker types and the victim's machine executes.
His live demo used two terminals. One was a €5 Ubuntu server he had bought, with
nothing installed on it, playing the attacker's machine and listening on port
4242 with nc -lvn. The other was his own laptop, playing the victim. He ran the
bash one-liner on the victim, and the attacker terminal immediately received an
interactive shell on the victim machine. One command.
The part that makes this work everywhere is the network direction. Khodami pointed out that his laptop was tethered to his phone's hotspot on a private network with no public IP address. An attacker cannot reach in: routers and firewalls block incoming connections by default. His analogy is a house — you need a key to get in, but from inside there is a handle and you can simply walk out. Outbound is open by default, so the victim opening the door from the inside is all that is required.
mvn install Is Enough
The obvious objection is that nobody would paste that command. Khodami's response
is that nobody has to. He created an empty Spring Boot project from Spring
Initializr and made exactly one change: he added a dependency on
com.google.code.gson in pom.xml. He never wrote a line of code that used it.
Running mvn install — during the test phase — produced the same reverse shell.
He classifies this one as a compromised build environment: the malicious
behaviour executes as part of the build itself, before any application code runs
and before anything is deployed.
npm install express@latest Is Also Enough
He repeated the exercise in the Node ecosystem: mkdir, npm init, then
npm install express@latest — the most downloaded npm package in the world, or
so his intent was. The install handed interactive access to his machine to
someone else. This one he classifies as dependency confusion, and he notes
that building the malicious Express package took him about half an hour. He is
explicit that no part of it is hard: the building is simple, and the remaining
step is finding a repository without enough security to publish into.
The clean version of this attack is worth stating plainly: the victim did not run untrusted code deliberately, did not deploy anything, and did not even use the library they installed.
The Five Categories
Khodami steps up a level from the demos to name five kinds of supply chain risk. The first is third-party vulnerabilities — the familiar baseline, where a dependency you use turns out to have a security issue and you have to update it. The other four are the ones teams think about less: dependency confusion, software supply chain hijacking, compromised build environment, and counterfeit components.
His two package-manager demos come from that second group. The Maven one was a compromised build environment; the npm one was dependency confusion.
Architecture And Data Flow
The following diagram summarises the dependency-confusion path from the npm demonstration, from a version range to a shell. It is the writer's synthesis of the narrated demo, not a reproduction of a slide from the talk. The Maven demo reached the same endpoint by a different route: a compromised build environment, where the malicious code ran during the build's test phase rather than being selected by version resolution.
flowchart TD
A["Project declares a dependency
with a version range or 'latest'"] --> B["Package manager resolves
across configured repositories"]
C["Attacker publishes package with
matching name at version 1.999.999"] --> B
B --> D["Resolver selects the highest version:
the attacker's artifact"]
D --> E["npm install lifecycle script runs
attacker-controlled code"]
E --> F["Victim machine opens an
OUTBOUND connection to attacker"]
G["Firewall / router blocks inbound,
permits outbound by default"] --> F
F --> H["Attacker receives interactive shell
on the victim machine"]How Dependency Confusion Actually Resolves
Khodami traces the trick back to a bored researcher during the pandemic period, and stresses how little sophistication it needs. The setup is an ordinary internal one. A strong team in your company publishes a shared library to a private repository. You trust them, and you have good automated tests, so you pin only the major version and let the minor and patch float to the newest available.
Your package manager is configured with several repositories, private and
public. When resolution runs, it looks for the newest version matching your
range. If a package with the same coordinates exists on a public repository at
version 1.999.999, the resolver has no notion that the number looks absurd —
it was told to fetch the latest, and that is the latest. A human reviewer would
find the version suspicious instantly; Maven and npm do not.
This is why namespace control is his first recommendation: if internal artifacts carry an organisation-specific prefix and you have reserved that namespace on the public registries, an attacker cannot publish a colliding name in the first place.
Nor is this a rare event. Khodami's suggestion is to simply search for supply chain attacks on npm: you will find companies being compromised this way every day. Google, Meta and Microsoft were all hit when this class of attack first emerged.
The Size of the Attack Surface
The reason a single weak package matters is transitive reach. Khodami's figure for a minimal Spring Boot "Hello World" is that you have actually imported roughly 49 dependencies — he cites 49 in one place and 45 later in the talk, so treat it as "around four dozen" rather than an exact count. For Node, installing Express alone pulls in 65 dependencies while you see one line in your manifest.
Each of those is an independent attack vector. His characterisation of the weakest link is the unpaid maintainer — a developer in Nebraska who has kept a five-kilobyte library alive for twenty years, has never been paid for it, and is currently on holiday. Social engineering or credential theft against that person is enough, and compromising the small library gives access into the larger ones that depend on it. He is emphatic that this is not hypothetical: it had happened as recently as two weeks before the talk.
The historical record supports the frequency claim. Supply chain attack is not a new front — Khodami dates its cybersecurity form to Stuxnet, fifteen or twenty years ago, and the general concept in human commerce to a thousand years ago — but headline incidents now arrive annually. He lists SolarWinds and Log4j, then 2025's Kubernetes ingress and Next.js incidents, and a large npm compromise in 2025 affecting a project with two billion weekly downloads.
And the response is slower than teams believe. Three years after Log4Shell, Khodami says 13% of people were still downloading the vulnerable version. Somebody near you is still pulling it.
Classic Vulnerabilities Have Not Gone Away
Before moving to defences, Khodami pushes back on the idea that SQL injection, XSS, and path traversal are solved problems. Comparing the OWASP Top 10 for 2017 and 2021, he notes items shifting order rather than disappearing. His stated expectation — attributed to security experts rather than to a published list — is that supply chain attack will appear as a new item in the next OWASP report, most probably in the top three.
His advice to engineers here is unusually blunt and is a personal opinion drawn from his consulting experience: if you have never actually performed a SQL injection hands-on, theory is not enough. Close the laptop, register for hands-on training, do it once, and only then commit code.
The reason classic bugs still matter in a supply chain talk is chaining. He walks through a plausible escalation: a SQL injection in your application gives an attacker a foothold; the Postgres instance has its own vulnerability permitting arbitrary command execution; that Postgres runs in a container whose base image has a flaw allowing root; the pod runs on a Kubernetes version with a privilege escalation path. The attacker is now king of the castle because of one injection bug. It sounds like a contrived chain, but attackers run automated scripts that try everything once they are inside.
AI Raises the Hit Rate
Khodami showed two package names side by side and asked the audience to spot the difference. Nobody could, and he said he could not either — nor could he catch it in a pull request. He referenced the person who discovered the xz backdoor by noticing a small connection delay (the transcript renders the library name and the delay figure imprecisely; the incident is the 2024 xz-utils backdoor) as the sort of engineer who might, and himself as someone who would not.
The question that follows is why an AI assistant would give you a wrong package name at all. His answer has three parts. LLMs can be poisoned — he cites an Anthropic report finding that roughly 250 documents are enough to influence a large model, which he calls almost nothing. Registry statistics can be faked, so manually checking download counts on npm to identify the real package is not reliable. And freely available models on Hugging Face have been found to be harmful in their own right. He is careful to say he still needs to read more about that last point. His summary: the AI era is bright, but full of terror.
Act II: A Tiered Defence Programme
Khodami organises the controls by how long they take to adopt: critical items you should pick up this week, essential items taking a month or two, and advanced items needing strategic planning, budget, and platform engineering support.
Critical
| Control | What it does |
|---|---|
| Naming convention and namespace reservation | Agree an organisation-wide prefix for internal artifacts, then reserve that namespace on public registries such as npm and NuGet so nobody else can publish under it. |
Pin versions; never latest |
The Express demo worked because of @latest. A specific version enables most of the other protections. |
| Package install checks | Maven strict checksum verification against Maven Central, enforcer plugin rules restricting what may be pulled, and package signature verification wherever the package manager supports it. |
--ignore-scripts for npm |
Most libraries have no legitimate reason to execute anything at install time. Khodami states this flag alone would have prevented his npm demo. |
npm audit |
Checks the packages actually present in node_modules against known issues. |
| Commit the lock-file | He has met multiple squads who put package-lock.json in .gitignore and calls that very wrong: the lock-file is what guarantees the deployed tree matches the one you tested. |
| Remove unused dependencies | The Gson import was never used and was still fatal. |
Essential
| Control | What it does |
|---|---|
| Stick to official repositories | He has seen engineers paste repository configuration from ChatGPT or Stack Overflow into pom.xml or settings.xml to fix an error, silently adding unofficial sources. |
| Proxy repository with filters | Nexus Repository or JFrog can be configured with rules rejecting packages whose names should never come from a given upstream. |
| Repository filters in the package manager | For teams without a proxy repository, Maven and Gradle support repository filtering directly. Khodami credits a colleague's blog post for making the setup tractable — it is not easy to do by hand. |
| Renovate or Dependabot | Gives you version pinning and automated update pull requests simultaneously. He puts initial setup at an hour or two. |
| Immutable release versions | Once 1.1.1 is published, nobody may overwrite it — including an attacker. If you shipped a mistake, release a patch version instead. |
| Dependency scanning | Enumerates what you actually depend on, and produces an SBOM. |
Advanced
A dependency firewall is a proxy that enforces policy at fetch time: block any package carrying, for example, a high-severity vulnerability. Some implementations go further and hide the offending version from search entirely, so a request for the latest version returns the latest safe version. Others impose a 24- to 48-hour quarantine on brand-new releases to let a version settle before anyone can pull it. (Writer's note: that quarantine is the control most directly aimed at the freshly published malicious artifact used in his demos; Khodami describes the mechanism but does not draw that connection.) Khodami says only two such products exist as far as he knows, Nexus Firewall and JFrog Xray, and that they are expensive.
Signing artifacts lets you verify later that what you are running is what you built. He singles out container images as the easiest and highest-value case, because you can sign at build time and then enforce at the Kubernetes level that no pod may start from an unverified image.
Monitoring SBOMs is the one he calls most important, and the reasoning is the Log4j reasoning: your SBOM was clean at deploy time, and stays that way in your records, while the world discovers new vulnerabilities in dependencies you are already running. Only continuous monitoring closes that window.
SBOMs in Practice
A Software Bill of Materials is the inventory a dependency scanner produces — available as XML, but Khodami works with the JSON form. It records the application, every dependency including transitive ones, versions, where each was downloaded from, and licences.
The licence field is worth attention because it solves a non-security problem with the same artifact. His example is PDF generation in the Java ecosystem: some libraries carry licences that require you to open-source your project if you use them. In a financial institution, that is not an option, and the SBOM is where you enforce the rule. The same applies to policies restricting libraries originating from particular countries.
You can generate an SBOM from source code, from a container image, from the built artifact such as a JAR, or at runtime with help from cloud providers. His tool recommendations are specific:
- OWASP dep-scan — free and open source, and his "jack of all trades" pick because it handles source, artifact, and container image scanning. It fits into a pipeline with rules to fail the build past a threshold.
- Spring Boot 3.3+ — produces an SBOM out of the box. Older or non-Boot Java projects need one added Maven dependency.
- Aqua Trivy — his preference for container images, based on a benchmark he ran against the available tools roughly six months before the talk, in which Trivy identified the most vulnerabilities. He believes the Docker CLI's built-in scanning may use Trivy as well, but says so tentatively. Treat the ranking as perishable: a six-month-old benchmark of a fast-moving tool category is worth re-running rather than inheriting.
- Dependency-Track — free, open source, and his recommendation for storing SBOMs organisation-wide. He benchmarked it against expensive commercial products and found its continuous scanning and searchability strong enough to call it a decent solution outright.
Paid tools differ mainly in maintaining a premium vulnerability database beyond public feeds, which can surface some issues earlier. Cloud-focused commercial scanners additionally infer which resources have public internet exposure, which feeds prioritisation.
Act III: What Resilience Buys You
Khodami's Log4Shell story is the payoff for all of the above. A Minecraft server was compromised in December, just as people were leaving for the Christmas holiday. The news spread and phones started ringing at financial institutions and e-commerce companies who initially could not see what a Minecraft server had to do with them.
The four questions every organisation then had to answer were: which applications are affected, who do we contact, how do we fix it, and how do we even detect whether we have it. Khodami's own team fixed it within an hour. He has worked with clients who were occupied with Log4Shell for a year — not because their engineers were slower, but because they had no way to answer question one.
The architecture that produces the one-hour answer is unglamorous: collect an SBOM for every application, server, and environment including test, and store them centrally. Because SBOMs are JSON, he suggests something like MongoDB. When the next crisis lands, you query the store for the affected coordinate. Store a contact person per application in the same document and you have answered the second question too. Store business-criticality metadata and you have a remediation order. Because a new deployment emits a new SBOM, you also get live progress — his illustration is watching an affected population fall from 1,000 applications to 500.
Severity Is Not Priority
He closes the technical argument with a comparison. Two vulnerabilities: one scored 5.9 out of 10 on CVSS, one scored a critical 10 out of 10. Which do you fix first? An audience member answered "the one that affects you", which Khodami accepted as the architect's "it depends".
The context he adds inverts the naive answer. The 5.9 sits in an internet-facing application holding customer PII and carries a high EPSS score — a live, daily-updated estimate of how likely it is that an exploit will actually be produced for that vulnerability in the near term. The 10.0 sits in an isolated network with a low EPSS score. You fix the medium one first, because priority and severity are not the same thing. His practical instruction is to decide in advance which metadata your organisation needs stored alongside each SBOM so this triage is possible under pressure rather than invented during the incident.
The Part Tools Cannot Fix
Khodami quotes Bruce Schneier — whom he introduces only as "the father of cryptography stuff, I think" — as saying "if you think that technology can solve security problems, you don't understand the technology and you don't understand the problems", and agrees. Working with 8,000 developers at his client, he says the technology is not the problem at all.
His framing of DevSecOps is that it is not a buzzword but a recognition that development, operations, and security currently sit in separate silos and need to work closer together. Involving security only at the end — asking for a pentest and a sign-off the day before a production release — is the failure mode. The discipline has three pillars: tools, governance, and people and processes. He considers the third the most important, because the cost of change is the most important factor in any architectural decision and the cost of changing people and processes is far higher than the cost of changing tools.
He is also concrete about the staffing pattern that follows. DevSecOps is a culture, but organisations increasingly also carry it as a role — held by someone with a working knowledge of all three pillars, embedded close to the DevOps teams and the developers shipping the product rather than sitting in a separate security function.
Shifting left means starting at design. His favourite item, which he admits is not a popular one, is threat modelling: before building, ask what happens if this application is compromised, what it has access to, and what follows from that — and let the answer change the implementation. Further right sit the four-eyes principle, which he notes many squads still try to bypass, and secret scanning. On the latter he relays experience with threat intelligence teams who pay for dark web monitoring: administrator credentials and tokens for a given company are on sale there, with an example price around €10,000. GitHub Advanced Security provides scanning by default; teams on private Git hosting need to arrange their own.
Shifting left does not mean abandoning the right-hand end. He closes the loop back to production and insists it remains the most important place to defend, for the reason his chained-escalation example established: the attacker's entry point is the SQL injection in your own application. Several strategies cover production; the one he has spent the talk on is continuous dependency monitoring via SBOM monitoring.
His closing image is Harvey Dent's line about dying a hero or living long enough to become the villain, applied not to people but to frameworks and dependencies that were once the right choice and are now the thing nobody knows how to remove. His conclusion is that continuous, in-flight upgrading is easier than a periodic big-bang migration project.
Trade-offs And Limitations
"Don't use latest" appears to contradict "use Dependabot". An audience member raised this directly. Khodami's resolution is that you should update continuously but not chase the newest release: target N-1, a version that has had time to be exercised by other people. Both Renovate and Dependabot can be configured for that. Occasionally a specific case forces you to the very latest, but it should be the exception. He pairs the N-1 configuration with pipeline automation: Dependabot raises update pull requests on a schedule, and if your unit and integration tests are good enough to gate them, accepted updates can flow through to production via continuous delivery without manual review.
Pinning breaks down in shared-library graphs. A questioner described the
common failure: five internal libraries each pin urllib to a slightly different
patch version, and the resolver either cannot find a solution or falls back to
the oldest. Khodami had no general answer beyond "it depends" and "give it a
try". His practical fallback is that most organisations only consume ten or
twenty internal libraries, so manual handling or a purpose-built script is
viable — he cites a team who wrote a Python script to check versions and open
pull requests when Renovate could not express their requirement.
Lock-file support is uneven across ecosystems. Asked about pinning to a hash rather than a version, Khodami's answer is that this is precisely what a lock-file already does, and the real work is configuring your pipeline to install from the lock-file rather than the manifest. Support varies: npm, Yarn, and Gradle provide it out of the box; pip requires configuration; Maven has no native lock-file and needs plugins.
The package managers themselves are slow to improve. Asked whether registries are getting more robust so that every team does not have to build workarounds, Khodami said they are working on it but the process is very slow and he does not know why. He cites npm adding account-level measures and invalidating all existing tokens as recent progress, notes that security experts publicly ask why Microsoft is not moving faster on npm, and says Maven is likewise missing features. His view is that this is partly a demand problem and users should ask for more.
Mass remediation can be bottlenecked by build capacity, not by detection. A questioner reported that their Log4j problem was a CI/CD pipeline overloaded by rebuilding all their software. Khodami did not have a packaged solution: he suggested it may need something in-house, and that the answer depends on experimenting with tools to find one covering your specific case — mentioning Qualys as an example of a vendor that covers situations like on-premises environments. (Writer's addition, not stated in the talk: SBOM metadata still helps you order the rebuilds even when it cannot make the pipeline faster.)
The freshness quarantine cuts both ways. A dependency firewall that holds brand-new releases for 24 to 48 hours delays a legitimate security patch by exactly the same window it delays a malicious upload. Khodami presents the mechanism without addressing that tension, so a team adopting it needs a deliberate exception path for urgent fixes.
Detection tooling does not address a compromised human. The Nebraska maintainer scenario, credential theft, and dark web token markets sit outside what any scanner will tell you.
Practical Takeaways
- Sequence the work by cost, not by fear. Khodami's critical tier is configuration your team owns today; the essential tier needs a month or two and some coordination; the advanced tier needs budget and platform engineering. Starting at the advanced tier is how these programmes stall.
- Treat "we can enumerate our dependencies in minutes" as the readiness test. The difference between a one-hour and a one-year Log4Shell response was inventory, not engineering skill.
- Make the SBOM store a queryable system, not an archive. Khodami's one-hour response came from being able to run a query against every environment at once; that only works if collection is automatic on every deploy.
- Prove the risk to your team rather than describing it. Khodami's demos are
reproducible in a sandbox, and a live reverse shell from
mvn installchanges a conversation that a slide about supply chain risk does not. - Audit what your build executes, not just what it downloads. The Gson demo compromised a machine during the build, before deployment and without the library ever being called.
- Budget for the people-and-process work. By Khodami's own ranking it is the highest-cost and highest-value pillar, and it is the one most often left out of a security tooling roadmap.
Key Terms
- Reverse shell — A shell session established by having the victim machine connect outbound to the attacker, so that inbound firewall rules never apply.
- Supply chain attack — Compromising software by compromising something it depends on, rather than attacking it directly.
- Third-party vulnerability — The baseline category: a security issue in a dependency you already use, which you address by updating it.
- Dependency confusion — Publishing a package matching an internal package's coordinates at an artificially high version so that a resolver following a version range prefers the attacker's artifact.
- Software supply chain hijacking — Taking over a legitimate package or the account that publishes it, so that malicious code arrives under a name and channel the consumer already trusts.
- Compromised build environment — Malicious code that executes during the build or install lifecycle rather than at application runtime.
- Counterfeit component — A package impersonating a legitimate one, including through typosquatted names.
- Transitive dependency — A dependency pulled in by one of your dependencies rather than declared by you.
- Lock-file — A committed record of the exact resolved dependency tree, including hashes, used to reproduce the tested tree at deploy time.
- SBOM (Software Bill of Materials) — A machine-readable inventory of an application's components, versions, origins, and licences.
- Dependency firewall — A policy-enforcing proxy that blocks, hides, or quarantines packages at fetch time based on vulnerability and freshness rules.
- CVSS — The standard severity score for a vulnerability, from 0 to 10.
- EPSS — A continuously updated probability estimate for a vulnerability being exploited in the near term; used alongside CVSS and deployment context to set remediation priority. (Khodami describes it in the talk as the likelihood that attackers will manage to produce an exploit within roughly a day to 30 days.)
- Threat modelling — A design-time exercise asking what an attacker gains if this component is compromised, and adjusting the design accordingly.
- Four-eyes principle — Requiring a second person to review a change before it lands.
- N-1 versioning — Deliberately tracking one release behind the newest, so updates stay current without being the first to run untested code.
The through-line is that none of the defences Khodami recommends are exotic.
Pinned versions, committed lock-files, --ignore-scripts, a reserved namespace,
and a queryable store of SBOMs are all achievable with existing free tooling and
a few weeks of attention. The reason we are not ready for the next Log4Shell is
not that the countermeasures are missing; it is that most organisations discover
they need an inventory only on the day they need to query it.
Reference: Soroosh Khodami, Are We Ready for the Next Cyber Security Crisis Like Log4shell?, InfoQ Dev Summit Munich, published by InfoQ on March 30, 2026. For the material he covers only in passing, he points the audience to a DevSecOps guideline resource linked from his slides, which sets out each of the steps he demonstrated along with the technical implementation detail.