Category: Security
Difficulty: Medium
Description:
S3PresignService generates its signing secret with randomBytes(32) as an instance field, so the secret is new on every process start. Presigned evidence upload URLs handed to a user before a restart are signed with a key that no longer exists afterwards, and two replicas sign with different keys, so a URL issued by one instance is not reproducible by another. This is the same defect class as an ephemeral signing key, and it makes the signature meaningless as a verification mechanism.
There is a second, larger problem behind it: the class documents itself as returning a simulated pre-signed URL, and no code anywhere verifies the signature it produces. This issue covers making the secret stable and configurable. Integrating a real object store is separate work.
Location:
src/common/services/s3-presign.service.ts
src/escrow/escrow.service.ts
src/escrow/buyer-dispute.service.ts
Example commits:
fix(security): load the presign secret from configuration
test(security): assert presigned URLs are reproducible across instances
Acceptance Criteria:
Technical Notes:
Follow the pattern used for SEP10_SIGNING_SECRET: validate in Joi, document in .env.example, throw on absence rather than defaulting. Do not implement real S3 integration in this PR.
Before you start
- Setup: CONTRIBUTING.md → Development Setup. Use Node 22 (
nvm use), run npm ci rather than npm install, and run npx prisma generate after installing. Skipping that last step makes npm run typecheck fail with Module '"@prisma/client"' has no exported member — a missing step, not a broken checkout.
- Tests that authenticate: use
bearer() from test/auth-helper.ts. Sending a bare Stellar address as a bearer token returns 401. See Writing Tests That Need Authentication.
- Branch from the latest
dev and open your pull request against dev, not main. dev is the default branch; main is the released baseline. If you branched earlier, rebase onto dev.
Category: Security
Difficulty: Medium
Description:
S3PresignServicegenerates its signing secret withrandomBytes(32)as an instance field, so the secret is new on every process start. Presigned evidence upload URLs handed to a user before a restart are signed with a key that no longer exists afterwards, and two replicas sign with different keys, so a URL issued by one instance is not reproducible by another. This is the same defect class as an ephemeral signing key, and it makes the signature meaningless as a verification mechanism.There is a second, larger problem behind it: the class documents itself as returning a simulated pre-signed URL, and no code anywhere verifies the signature it produces. This issue covers making the secret stable and configurable. Integrating a real object store is separate work.
Location:
src/common/services/s3-presign.service.tssrc/escrow/escrow.service.tssrc/escrow/buyer-dispute.service.tsExample commits:
Acceptance Criteria:
src/config/config.module.tsand documented in.env.examplenpm run test:covpasses and overall coverage stays at or above 70%Technical Notes:
Follow the pattern used for
SEP10_SIGNING_SECRET: validate in Joi, document in.env.example, throw on absence rather than defaulting. Do not implement real S3 integration in this PR.Before you start
nvm use), runnpm cirather thannpm install, and runnpx prisma generateafter installing. Skipping that last step makesnpm run typecheckfail withModule '"@prisma/client"' has no exported member— a missing step, not a broken checkout.bearer()fromtest/auth-helper.ts. Sending a bare Stellar address as a bearer token returns 401. See Writing Tests That Need Authentication.devand open your pull request againstdev, notmain.devis the default branch;mainis the released baseline. If you branched earlier, rebase ontodev.