Repository navigation
Conversation
…d a test pins the field order BitMiracle-AI#90 reads sha256(path:operation:user:token[:exp]) as sha256(secret || data) and asks for HMAC on both ends. That would break the one thing the format exists for: the official SDK hashes exactly this string before a URL ever reaches us (js-sdk/src/sandbox/signature.ts sends it through crypto.subtle SHA-256), and real envd verifies the same digest — an HMAC on this side rejects every SDK-minted URL. So the change is the part of the report that is ours to act on: - envd-client.ts and signing.ts now say the shape is inherited, name the SDK file, and spell out why length extension has no graft point in it: the material is rebuilt from parsed params in this order, the token sits fourth of five, and the only possible trailing component parses as a number. - The TTL comment states what the URL is: a 15-minute capability with no revocation — destroying the sandbox or rotating the API token does not end it, only the clock does. - btoa(String.fromCharCode(...bytes)) becomes a loop. The spread throws RangeError once the buffer grows (measured at 400 KB) and the conversion is byte-for-byte the same, so the console keeps minting what the SDK mints. - A compat test pins the field order as a contract: a reordered material and one carrying an extra component both answer 401, and the canonical order still opens the door.
ursasi
force-pushed
the
signed-url-format-is-inherited
branch
from
October 7, 2026 14:06
c93df2f to
2c1b9e2
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Related to #90. I did not switch to HMAC, and I think that part of the report
would do harm: the construction is not ours to pick.
What the format is
It is the E2B wire format, on both ends. The official SDK hashes exactly this
string before a URL ever reaches us —
packages/js-sdk/src/sandbox/signature.tsbuilds
path:operation:user:envdAccessToken[:exp]and sends it throughcrypto.subtle.digest('SHA-256', …)— and real envd verifies the same digest.This repo already says so in three places (
signing.ts's header,envd/files.ts:186, andapp.test.ts's "the SDK's formula, rewritten ratherthan imported"), and the daemon has a test that accepts an SDK-minted
signature. An HMAC on the verification side would reject every URL minted by
the SDK the project exists to be compatible with.
On the length-extension worry: the construction has no graft point, and not by
luck of one field's position — the verifier rebuilds the material from parsed
query params in a fixed order, the token is fourth of five, and the only
component that can follow it parses as a number. There is no place for an
attacker-chosen suffix to survive that reading. What the report rightly flags
is that this reasoning should be written down where the next reader will find
it instead of being re-derived — that is what this PR does.
On "no test would notice" a reordering: several already would (
app.test.tsrewrites the SDK's formula,
compat.test.tsandsandbox-proxy.test.tsmintit,
e2e/src/console.test.tsmints it in the browser). I added the missingone: a signature over a reordered material, and one over a material with an
extra component, both refused.
What changed
signing.tsandenvd-client.tsstate that the shape is inherited, name theSDK file, and spell out why there is no extension point. Same for the TTL:
the comment now says the URL is a 15-minute capability with no revocation —
destroying the sandbox or rotating the API token does not end it.
btoa(String.fromCharCode(...bytes))became a loop. This part of the reportis real: the spread throws
RangeErroronce the buffer grows (I measured400 KB). The conversion output is byte-for-byte identical, checked against
the spread on the same digest.
still opens the door.
Verification
pnpm vitest runinpackages/server: 651 passed, 2 skipped (the Dockercontract suite).
tsc --noEmitclean; the console file type-checks too(target ES2023, so the loop is fine).
biome checkreports the same 10pre-existing
noUnsafeOptionalChainingfindings incompat.test.tsas beforethe change.
If you do want a signature scheme of our own on top of the SDK-compatible one,
I am happy to work on that as a separate design — but it has to be a second
URL form, not a change to this one.