Grey-Box // Coordinated disclosure - window closed

Ninety days of silence in an AI sandbox platform

On 8 June 2026 I filed four security advisories against e2b-dev/infra, the open-source platform behind E2B's AI sandboxes. Ninety days later all four are still open. Two half-fixes were shipped quietly and never mentioned. Neither of my two questions - a remediation timeline, and who requests the CVEs - has been answered. This is the record, the findings by class, and the exploit detail I am deliberately not publishing.

4 findings, all unpatched 1 Critical · 2 High · 1 Medium No CVE assigned Advisories unpublished Day 92 at publication

"Thank you for the report. I sincerely apologize for the delay on my end. I've forwarded this to our engineering team for review. I'll get back to you as soon as they go over it."

E2B security contact, 2 July 2026 · the last substantive reply, followed on 8 July by "I've bumped the internal thread", and then by nothing

Disclosure record
Project
e2b-dev/infra
Reported
2026-06-08
Findings
4 · Critical 9.6, High 8.5, High 7.4, Medium 5.0
Status at publication
All four unpatched
Vendor engagement on the advisory records
None. All four remain in triage; no maintainer has commented on any of them in 92 days.
Fixes shipped
Two partial, both unannounced: an input check covering one half of one finding (9 June, 10 June), and error sanitization covering the observable half of another (26 June).
CVE
None assigned
Advisories
Filed privately, still unpublished
Scope of testing
The open-source platform only, on infrastructure I own. No E2B-operated service was touched at any point.

01 What this is, and what it is not

E2B publishes e2b-dev/infra under Apache-2.0. It is the platform behind their AI sandboxes, and they document and support running it yourself: their site advertises self-hosted, on-premises and bring-your-own-cloud deployments alongside the managed service. This piece is about that published code.

It is not about E2B's hosted service. I have not tested it and I will not. Everything below was done on my own hardware, against builds I compiled from the public repository, using the vendor's own documented local development environment. What their production runs, how it is segmented, and how it is configured are unknown to me, and I make no claim about it. Their reference infrastructure code is also, on one of these four findings, explicitly not affected - I will say exactly where, because that boundary matters more to me than a bigger headline.

So read this as: four unfixed flaws in a widely deployed open-source platform, verified end to end on the deployment the vendor themselves document, with the vendor silent for three months.

02 The four findings, by class

I am describing these at the level of the weakness class and the trust boundary each one crosses. No file paths, no line numbers, no payloads, no proof-of-concept code. Section 04 explains why.

  • CriticalAn internal control plane that authenticates nothing. A core service carries no authentication and no per-request authorization. Anything that can reach its port can drive every tenant's workloads on that node and read build artifacts belonging to other tenants. The identity the caller claims is used for labelling, not for a decision. Authentication alone would not close it: the ownership check is missing as well.
  • HighA tenant boundary made of a string prefix. A tenant-supplied value flows unvalidated into a storage key that is scoped by prefixing the tenant's own identifier. Because the join normalises the path, the prefix can be walked out of, and one tenant's build reads another tenant's cached build artifacts - the place proprietary source and credentials sit. A format check for this exact value already exists in the codebase; it is simply never applied on this path.
  • HighA guessable default signing seed. The shipped environment template and the CI action both carry a working, trivially guessable default for the secret that signs per-sandbox access tokens. Tokens derive deterministically from that secret and a public identifier, so on any deployment that inherits the default, the tokens are computable by anyone. Empty values are rejected; the known default is not. Narrow but real - see section 07 for exactly which deployments are affected, and which are not.
  • MediumA build pipeline that will fetch anything you name. A tenant-controlled reference makes the build host connect to a destination of the tenant's choosing and follow redirects to arbitrary internal URLs, with no allowlist and no block on private or link-local addresses. Blind: the response body does not come back. Notably the same codebase already applies a denied-network-range check in the two other places a tenant supplies a destination. This is the unguarded sibling.

Three of these four are the same failure in different clothes: a boundary that is asserted somewhere else in the system, and simply not enforced here.

03 How they were verified

A finding is worth what its evidence is worth, so here is exactly what was done and on what.

First, from source at current HEAD. I compiled the platform from the public repository at that day's main, on my own KVM host, and ran the findings against real microVMs. The tracked tree was clean, so the running binaries were unmodified upstream code, not a patched harness. The control-plane finding was confirmed with an ordinary client built from the project's own generated stubs, presenting no credentials at all; the server's own logs record each call completing successfully from an anonymous peer.

Then, on the vendor's own documented deployment. Source-level confirmation was not enough, because "the guard is missing" and "an ordinary tenant can actually do this" are different claims. So I stood up E2B's documented local environment exactly as their own guide prescribes - their compose stack, their database migrations, their seed script, the tenant API key their seed script prints, their service launch targets - and drove the attacks through the public API as a tenant. No code modifications. Two tenants, both created by their own seed script.

That second pass is what turned two of the findings from arguments into demonstrations. The build-cache traversal was performed end to end using nothing but a documented API call and an ordinary tenant key, and the artifact belonging to the other tenant was then read from inside the resulting sandbox. The token finding was confirmed against the live verifier rather than against itself: the running server issued a token, an offline computation reproduced it byte for byte from public inputs, and the forged value was then accepted by the service.

With a negative control, every time. The token test was run twice: once with a deliberately wrong value, once with the forged one. The wrong value was rejected, the request denied, the workload left untouched; the forged value was accepted and the workload resumed. Without that control the result proves nothing, because a check that never runs also never fails.

token verifier - control vs. forged (values withheld)observed · unmodified build
# same request, same endpoint, same paused workload. only the credential differs.

wrong value    -> HTTP 403   server: PermissionDenied     state after: paused
forged value   -> HTTP 204   server: OK                   state after: running

# the control establishes the check is real and executes.
# the second line establishes it passes with a credential derived from public inputs.

And one result that cuts against me. I also tested whether a tenant could reach the unauthenticated control plane from inside their own sandbox. They cannot: on a stock deployment those ports were unreachable from the sandbox while public destinations were not. So this is not a tenant-to-control-plane escape, and I have said so in the advisory. The attack vector is adjacent-network, which is what the severity score I filed already stated. A related non-finding, for completeness: the link-local metadata address reachable from inside a sandbox is the microVM's own metadata service, not the cloud provider's. There is no cloud-credential exposure there and I am not claiming one.

04 What is withheld, and why

All four findings are unpatched on the day this is published. So this write-up carries the weakness class, the trust boundary, and the timeline - and nothing that shortens the distance between reading it and exploiting it.

No file paths, no line numbers, no request bodies, no payload strings, no default values, no proof-of-concept code, no harness. Those live in the private advisories and on my disk. I told the vendor in writing that this is what publication would look like, before the window closed, and this is that.

The reason is not politeness. Anyone can self-host this platform, and some of them are running it right now. Publishing a working recipe against unfixed code transfers the cost of the vendor's silence onto its users, who did nothing wrong. Section 08 is what those users can act on today; it is deliberately the most actionable part of this page.

If the findings are fixed, I will publish the technical detail in full, and I would rather write that version.

05 The corrections I made to my own reports

Before describing the vendor's silence I have to describe my own errors, because there were several and they were mine.

In August I ran an adversarial audit of my own four filings - not "is the bug still there", which I had checked repeatedly, but "is every sentence I wrote actually supported by my own evidence files". It was not. Roughly two dozen claims were overstated and nine were unsupported. The findings themselves survived; a good deal of the language around them did not.

Concretely, and all in the vendor's favour: two artifact-size figures I reported were wrong and contradicted my own logs. I had written that data was "streamed" when the test read a few hundred bytes. I had listed a request-forgery primitive as a way to reach the control plane, which my own notes showed does not work because of a protocol mismatch. I described a build host as sharing a network with another service when every target I had actually reached was on the same machine. And I scored the seed finding Critical when the vendor's own reference infrastructure code makes it inapplicable to that deployment shape entirely - it is High, and I lowered it.

I corrected all four advisory bodies on 1 September, each with a dated revision note stating what changed, and I told the vendor what I had gotten wrong in the same message that told them the window was closing. The corrected text is the record; the original reports I emailed in June are superseded.

A researcher who has never had to correct himself has either been lucky or has not looked hard enough at his own work.

I am putting this in the write-up rather than quietly fixing it because a disclosure is a claim about someone else's engineering, and the only thing that makes such a claim worth anything is a demonstrated willingness to apply the same standard inward. If any statement on this page turns out to be wrong, I will correct it here, dated, the same way.

06 What the vendor did

Not nothing - and the accurate version is more interesting than "they ignored it".

Eleven hours after the reports were filed, a fix landed for one half of one finding: an input format check, applied to a single handler. The following day it was refactored, same author, same file, same single call site. Neither commit mentioned a security report. Neither touched the other half of that finding, which is the half that actually crosses a tenant boundary and is still open today. Two and a half weeks later a second change landed that sanitized the error messages of another finding, removing the feedback channel while leaving the underlying behaviour intact. Also unannounced. I missed that one for two months, found it in my own August audit, and have credited it in the advisory - it is a real fix and it did close a real information leak.

So the engineering side reads these reports and acts on them, quickly, and then stops at the part that is visible or easy. Meanwhile the advisory records themselves have never been touched: no comment, no severity discussion, no dispute, no remediation date, in 92 days. The email channel produced three courteous acknowledgements and then silence since 8 July.

The two questions I asked on 16 June, and asked again on 1 September, remain unanswered: when will these be fixed, and do you want to request the CVEs or should I. It is the second one that makes silence expensive, because for advisories on a GitHub-hosted project only the maintainers can request a CVE identifier. A reporter cannot. Silence there is not neutral; it withholds the identifier that makes the issue trackable by everyone downstream.

07 Who is actually affected

The honest ceiling, finding by finding, because a disclosure that overstates its blast radius is worth less than one that does not.

  • Self-hostersThe primary at-risk population. If you run this platform yourself, in your own cloud or on-premises, all four findings are live for you today unless you have hardened around them. The seed finding in particular depends on how you deployed: deployments built from the vendor's reference infrastructure code generate a random secret and are not affected, while a deployment that starts from the shipped environment template, or a CI pipeline that uses the shipped value, is.
  • Multi-tenantThe two most serious findings are tenant-isolation failures, so they matter in proportion to how much you are relying on that isolation. If separate customers, separate teams, or untrusted AI-agent workloads share one deployment, the boundary between them is thinner than the platform implies.
  • Single-tenantIf you run this for one trusted team and nothing hostile ever executes in it, these are hardening gaps rather than live risks. Real, worth fixing, not urgent.
  • Managed serviceOut of scope of this research and not assessed. I have not tested it and make no claim about it either way.

08 If you self-host this platform, do these four things

None of this requires knowing the technical detail I am withholding, and none of it depends on the vendor shipping anything.

Generate your own token-signing secret. Never inherit a value that shipped with the software, in an environment template, an example file, or a CI configuration. If you cannot say where your secret came from, replace it. Note that rotating it invalidates existing sandbox tokens, so plan the change.

Treat the internal control-plane port as fully trusted, because it is. Confine it to the specific hosts that must speak to it. It carries no authentication of its own, so your network segmentation is the whole control. Check that it is not bound wider than you assume, and check it from a workload's point of view rather than from your diagram.

Restrict what the build pipeline may reach outbound. Default-deny private, loopback, link-local and cloud-metadata ranges from the host that performs image pulls, and be aware that redirects can move the destination after the request starts. The same platform already applies this class of restriction elsewhere; apply it here yourself.

Assume the build cache is not a tenant boundary. If different tenants' builds share one storage scope, treat cross-tenant reads as possible until the vendor ships a containment check, and keep anything you would not share out of build layers.

09 Why publish now

Ninety days is the convention, and I told them the date twice: once on 16 June when I set it, once on 1 September when it was five days out. Nothing here is a surprise to the vendor.

Publishing a class-level description of an unfixed flaw is a real cost and I do not pretend otherwise. It is smaller than the alternative. Self-hosters currently cannot make an informed decision about a platform they are running, because the information that would let them is sitting in four private records that only the vendor can publish. Section 08 exists so that a reader who runs this can act this afternoon, and every one of those four actions is available without knowing a single line of the code.

The window closing is not a punishment. It is the deadline that makes coordinated disclosure a coordination mechanism instead of an indefinite option held by whoever received the report.


10 Disclosure timeline

  • 2026-06-08Four advisories filed privately against e2b-dev/infra. Reporter credit accepted on all four the same day.
  • 2026-06-09An input check lands covering one half of one finding, eleven hours after filing. No mention of a security report.
  • 2026-06-10The same check is refactored, same single call site. The other half of that finding is untouched.
  • 2026-06-16Emailed the vendor's published security address. Asked for a remediation timeline and for a decision on CVE handling. Sent all four reports on request, same day.
  • 2026-06-26A second unannounced change lands, sanitizing the error output of another finding. The underlying behaviour is unchanged.
  • 2026-07-02Vendor: "I've forwarded this to our engineering team for review."
  • 2026-07-08Vendor: "I've bumped the internal thread and will let you know as soon as I get an update." Last contact received.
  • 2026-08-26Adversarial audit of my own four filings. Roughly two dozen overstated claims and nine unsupported ones identified in my own text.
  • 2026-09-01Re-verified all four against that day's main, first from source, then end to end on the vendor's own documented deployment. Corrected all four advisory bodies, including one severity reduction. Emailed the vendor the corrections, the re-verification, and the publication date.
  • 2026-09-06Ninety-day window closes. No response.
  • 2026-09-07Re-verified all four one final time against that day's main, one reviewer per finding, bounded and unbounded history. Forty-two commits had landed since 1 September and several touched files on these paths - none added a guard. All four unchanged.
  • 2026-09-08This page published. All four findings unpatched, no CVE assigned, advisories still unpublished by the vendor.

The four advisories remain private and cannot be linked here, because on a GitHub-hosted project only the maintainers can publish them. If they are published, or if CVE identifiers are assigned, I will add the references to this page. I have asked the vendor to request the identifiers; if that stays unanswered I will pursue assignment through the CVE Program's process for the case where the supplier will not.

To E2B, plainly: the offer from 1 September stands. Ship fixes and I will re-test them against your patches before you cut a release, coordinate the wording, and publish the full technical detail on your timeline rather than mine.