Skip to content

S3 presign secret is regenerated on every process start #413

Description

@Omoboi-dev

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:

  • The signing secret is read from configuration, not generated at construction
  • The variable is declared in the Joi schema in src/config/config.module.ts and documented in .env.example
  • The service fails with a clear error when no secret is configured, rather than falling back to a generated or literal value
  • A test asserts two separately constructed instances with the same configured secret produce identical URLs for identical input
  • A test asserts a different secret produces a different signature
  • A test asserts the expiry timestamp is included in the signed material, so it cannot be altered independently
  • npm run test:cov passes 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

  • 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Stellar WaveIssues in the Stellar wave programcomplexity: medium150 pts. New endpoint, service method, integration testsecuritysecurity checks

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions