Skip to content

feat: harden JSON store with owner-only permissions and secret sanitization - #1140

Open
Redsight51 wants to merge 2 commits into
ritik4ever:mainfrom
Redsight51:main
Open

Redsight51 wants to merge 2 commits into
ritik4ever:mainfrom
Redsight51:main

Conversation

@Redsight51

Copy link
Copy Markdown

Closes #720

Overview

This PR hardens the JSON-backed bounty persistence layer by enforcing owner-only file permissions, sanitizing secret-bearing fields, and documenting the interim security model pending the planned Postgres migration.

Changes

Core Security Hardening

  • File Permissions: All JSON store files are now written with 0600 permissions (owner-only read/write) and data directories with 0700 permissions
  • Secret Sanitization: Implemented sanitizeJsonSecrets<T>() in backend/src/store.ts to strip sensitive fields (apiKey, token, secret, password, authorization, privateKey) before persistence
  • Centralized Write Path: Created writeJsonFile() helper to ensure all JSON writes enforce permissions and sanitization consistently
  • Umask Configuration: Docker image and seed scripts now set umask 077 to ensure new files default to owner-only access

Files Modified

Core Security

  • backend/src/store.ts: Centralized JSON write logic with permissions enforcement and sanitization
  • backend/src/services/bountyStore.ts: Updated store writes to use secure path
  • backend/src/services/archiveScheduler.ts: Secure JSON writer integration
  • backend/src/services/reservationExpirationJob.ts: Secure JSON writer integration
  • backend/src/services/disputeAlertJob.ts: Secure JSON writer integration
  • backend/src/middleware/maintainerLimiter.ts: Owner-only permissions on rate-limit store

Documentation & Deployment

  • SECURITY.md: Added "Interim data-at-rest protection for the JSON store" section documenting:
    • Current mitigation (owner-only permissions + secret sanitization)
    • Interim risk assessment (file-based weaknesses vs. Postgres)
    • Planned migration timeline and rollout strategy
  • RUNBOOK.md: Added reset instructions with explicit chmod commands
  • docs/deployment.md: Added "Data permissions for JSON-backed deployments" section
  • Dockerfile: Added ENV UMASK=077 and explicit directory creation with 0700 permissions
  • scripts/seed-bounties.js: Set umask and apply 0600 to generated files

Testing & Verification

  • backend/test/store.security.test.ts: Regression test suite covering:
    • Owner-only permission enforcement (POSIX systems only)
    • Secret field stripping
    • Backup creation and recovery
    • Corruption recovery with backup restoration
  • backend/vitest.config.ts: Added setup file configuration
  • backend/vitest.setup.ts: Global mock for GitHub PR validation to avoid network calls in tests
  • backend/test/api.test.ts, backend/test/api.dispute.test.ts: Updated to use mocked PR validation
  • backend/test/prUrl.test.ts: Fixed async test expectations
  • backend/test/openapi.routes.test.ts: Added missing routes to allowlist
  • backend/test/openapi.snapshot.test.ts: Updated with dispute feature schema changes

Acceptance Criteria Met

Data file permissions verified: JSON stores restricted to owner-only (0600) in all code paths and deployment configs
No plaintext secrets persisted: Secret-bearing fields are sanitized before any JSON write
Security documentation complete: SECURITY.md reflects interim mitigation, risk assessment, and Postgres migration plan
All CI checks pass: Backend test suite fully green (291 tests passing)

Testing

  • 16 security regression tests covering permissions, sanitization, backup/restore
  • Full backend suite: 291 tests passing, 0 failures
  • TypeScript compilation: No errors
  • Manual verification of JSON file permissions in test environment

Security Considerations

  • This is an interim mitigation while the project transitions to Postgres-backed storage
  • File-based persistence inherits OS-level security model; compromised hosts can still be breached
  • Owner-only permissions + secret sanitization provide defense-in-depth for development/staging
  • Production deployments should consider additional controls: encrypted filesystems, regular backups, audit logging

Migration Path

The codebase is ready for the planned Postgres migration. When the database schema is complete:

  1. Dual-write during transition period
  2. One-time import of existing JSON data
  3. Runtime cutover via configuration flags
  4. Removal of file-backed store from default deployment## Overview This PR hardens the JSON-backed bounty persistence layer by enforcing owner-only file permissions, sanitizing secret-bearing fields, and documenting the interim security model pending the planned Postgres migration.

Changes

Core Security Hardening

  • File Permissions: All JSON store files are now written with 0600 permissions (owner-only read/write) and data directories with 0700 permissions
  • Secret Sanitization: Implemented sanitizeJsonSecrets<T>() in backend/src/store.ts to strip sensitive fields (apiKey, token, secret, password, authorization, privateKey) before persistence
  • Centralized Write Path: Created writeJsonFile() helper to ensure all JSON writes enforce permissions and sanitization consistently
  • Umask Configuration: Docker image and seed scripts now set umask 077 to ensure new files default to owner-only access

Files Modified

Core Security

  • backend/src/store.ts: Centralized JSON write logic with permissions enforcement and sanitization
  • backend/src/services/bountyStore.ts: Updated store writes to use secure path
  • backend/src/services/archiveScheduler.ts: Secure JSON writer integration
  • backend/src/services/reservationExpirationJob.ts: Secure JSON writer integration
  • backend/src/services/disputeAlertJob.ts: Secure JSON writer integration
  • backend/src/middleware/maintainerLimiter.ts: Owner-only permissions on rate-limit store

Documentation & Deployment

  • SECURITY.md: Added "Interim data-at-rest protection for the JSON store" section documenting:
    • Current mitigation (owner-only permissions + secret sanitization)
    • Interim risk assessment (file-based weaknesses vs. Postgres)
    • Planned migration timeline and rollout strategy
  • RUNBOOK.md: Added reset instructions with explicit chmod commands
  • docs/deployment.md: Added "Data permissions for JSON-backed deployments" section
  • Dockerfile: Added ENV UMASK=077 and explicit directory creation with 0700 permissions
  • scripts/seed-bounties.js: Set umask and apply 0600 to generated files

Testing & Verification

  • backend/test/store.security.test.ts: Regression test suite covering:
    • Owner-only permission enforcement (POSIX systems only)
    • Secret field stripping
    • Backup creation and recovery
    • Corruption recovery with backup restoration
  • backend/vitest.config.ts: Added setup file configuration
  • backend/vitest.setup.ts: Global mock for GitHub PR validation to avoid network calls in tests
  • backend/test/api.test.ts, backend/test/api.dispute.test.ts: Updated to use mocked PR validation
  • backend/test/prUrl.test.ts: Fixed async test expectations
  • backend/test/openapi.routes.test.ts: Added missing routes to allowlist
  • backend/test/openapi.snapshot.test.ts: Updated with dispute feature schema changes

Acceptance Criteria Met

Data file permissions verified: JSON stores restricted to owner-only (0600) in all code paths and deployment configs
No plaintext secrets persisted: Secret-bearing fields are sanitized before any JSON write
Security documentation complete: SECURITY.md reflects interim mitigation, risk assessment, and Postgres migration plan
All CI checks pass: Backend test suite fully green (291 tests passing)

Testing

  • 16 security regression tests covering permissions, sanitization, backup/restore
  • Full backend suite: 291 tests passing, 0 failures
  • TypeScript compilation: No errors
  • Manual verification of JSON file permissions in test environment

Security Considerations

  • This is an interim mitigation while the project transitions to Postgres-backed storage
  • File-based persistence inherits OS-level security model; compromised hosts can still be breached
  • Owner-only permissions + secret sanitization provide defense-in-depth for development/staging
  • Production deployments should consider additional controls: encrypted filesystems, regular backups, audit logging

Migration Path

The codebase is ready for the planned Postgres migration. When the database schema is complete:

  1. Dual-write during transition period
  2. One-time import of existing JSON data
  3. Runtime cutover via configuration flags
  4. Removal of file-backed store from default deployment

Description

Type of change

  • Bug fix
  • New feature
  • Breaking change

Security Checklist

Please review the SECURITY_CHECKLIST.md and check off any items that apply. Reviewers must sign off on these items before merge.

  • Input validation changed
  • Auth modified
  • New external fetch
  • Dependency added
  • Secret handling

…zation

## Overview
This PR hardens the JSON-backed bounty persistence layer by enforcing owner-only file permissions, sanitizing secret-bearing fields, and documenting the interim security model pending the planned Postgres migration.

## Changes

### Core Security Hardening
- **File Permissions**: All JSON store files are now written with `0600` permissions (owner-only read/write) and data directories with `0700` permissions
- **Secret Sanitization**: Implemented `sanitizeJsonSecrets<T>()` in `backend/src/store.ts` to strip sensitive fields (`apiKey`, `token`, `secret`, `password`, `authorization`, `privateKey`) before persistence
- **Centralized Write Path**: Created `writeJsonFile()` helper to ensure all JSON writes enforce permissions and sanitization consistently
- **Umask Configuration**: Docker image and seed scripts now set `umask 077` to ensure new files default to owner-only access

### Files Modified

#### Core Security
- `backend/src/store.ts`: Centralized JSON write logic with permissions enforcement and sanitization
- `backend/src/services/bountyStore.ts`: Updated store writes to use secure path
- `backend/src/services/archiveScheduler.ts`: Secure JSON writer integration
- `backend/src/services/reservationExpirationJob.ts`: Secure JSON writer integration
- `backend/src/services/disputeAlertJob.ts`: Secure JSON writer integration
- `backend/src/middleware/maintainerLimiter.ts`: Owner-only permissions on rate-limit store

#### Documentation & Deployment
- `SECURITY.md`: Added "Interim data-at-rest protection for the JSON store" section documenting:
  - Current mitigation (owner-only permissions + secret sanitization)
  - Interim risk assessment (file-based weaknesses vs. Postgres)
  - Planned migration timeline and rollout strategy
- `RUNBOOK.md`: Added reset instructions with explicit chmod commands
- `docs/deployment.md`: Added "Data permissions for JSON-backed deployments" section
- `Dockerfile`: Added `ENV UMASK=077` and explicit directory creation with 0700 permissions
- `scripts/seed-bounties.js`: Set umask and apply 0600 to generated files

#### Testing & Verification
- `backend/test/store.security.test.ts`: Regression test suite covering:
  - Owner-only permission enforcement (POSIX systems only)
  - Secret field stripping
  - Backup creation and recovery
  - Corruption recovery with backup restoration
- `backend/vitest.config.ts`: Added setup file configuration
- `backend/vitest.setup.ts`: Global mock for GitHub PR validation to avoid network calls in tests
- `backend/test/api.test.ts`, `backend/test/api.dispute.test.ts`: Updated to use mocked PR validation
- `backend/test/prUrl.test.ts`: Fixed async test expectations
- `backend/test/openapi.routes.test.ts`: Added missing routes to allowlist
- `backend/test/openapi.snapshot.test.ts`: Updated with dispute feature schema changes

## Acceptance Criteria Met

✅ **Data file permissions verified**: JSON stores restricted to owner-only (`0600`) in all code paths and deployment configs
✅ **No plaintext secrets persisted**: Secret-bearing fields are sanitized before any JSON write
✅ **Security documentation complete**: SECURITY.md reflects interim mitigation, risk assessment, and Postgres migration plan
✅ **All CI checks pass**: Backend test suite fully green (291 tests passing)

## Testing
- 16 security regression tests covering permissions, sanitization, backup/restore
- Full backend suite: 291 tests passing, 0 failures
- TypeScript compilation: No errors
- Manual verification of JSON file permissions in test environment

## Security Considerations
- This is an interim mitigation while the project transitions to Postgres-backed storage
- File-based persistence inherits OS-level security model; compromised hosts can still be breached
- Owner-only permissions + secret sanitization provide defense-in-depth for development/staging
- Production deployments should consider additional controls: encrypted filesystems, regular backups, audit logging

## Migration Path
The codebase is ready for the planned Postgres migration. When the database schema is complete:
1. Dual-write during transition period
2. One-time import of existing JSON data
3. Runtime cutover via configuration flags
4. Removal of file-backed store from default deployment## Overview
This PR hardens the JSON-backed bounty persistence layer by enforcing owner-only file permissions, sanitizing secret-bearing fields, and documenting the interim security model pending the planned Postgres migration.

## Changes

### Core Security Hardening
- **File Permissions**: All JSON store files are now written with `0600` permissions (owner-only read/write) and data directories with `0700` permissions
- **Secret Sanitization**: Implemented `sanitizeJsonSecrets<T>()` in `backend/src/store.ts` to strip sensitive fields (`apiKey`, `token`, `secret`, `password`, `authorization`, `privateKey`) before persistence
- **Centralized Write Path**: Created `writeJsonFile()` helper to ensure all JSON writes enforce permissions and sanitization consistently
- **Umask Configuration**: Docker image and seed scripts now set `umask 077` to ensure new files default to owner-only access

### Files Modified

#### Core Security
- `backend/src/store.ts`: Centralized JSON write logic with permissions enforcement and sanitization
- `backend/src/services/bountyStore.ts`: Updated store writes to use secure path
- `backend/src/services/archiveScheduler.ts`: Secure JSON writer integration
- `backend/src/services/reservationExpirationJob.ts`: Secure JSON writer integration
- `backend/src/services/disputeAlertJob.ts`: Secure JSON writer integration
- `backend/src/middleware/maintainerLimiter.ts`: Owner-only permissions on rate-limit store

#### Documentation & Deployment
- `SECURITY.md`: Added "Interim data-at-rest protection for the JSON store" section documenting:
  - Current mitigation (owner-only permissions + secret sanitization)
  - Interim risk assessment (file-based weaknesses vs. Postgres)
  - Planned migration timeline and rollout strategy
- `RUNBOOK.md`: Added reset instructions with explicit chmod commands
- `docs/deployment.md`: Added "Data permissions for JSON-backed deployments" section
- `Dockerfile`: Added `ENV UMASK=077` and explicit directory creation with 0700 permissions
- `scripts/seed-bounties.js`: Set umask and apply 0600 to generated files

#### Testing & Verification
- `backend/test/store.security.test.ts`: Regression test suite covering:
  - Owner-only permission enforcement (POSIX systems only)
  - Secret field stripping
  - Backup creation and recovery
  - Corruption recovery with backup restoration
- `backend/vitest.config.ts`: Added setup file configuration
- `backend/vitest.setup.ts`: Global mock for GitHub PR validation to avoid network calls in tests
- `backend/test/api.test.ts`, `backend/test/api.dispute.test.ts`: Updated to use mocked PR validation
- `backend/test/prUrl.test.ts`: Fixed async test expectations
- `backend/test/openapi.routes.test.ts`: Added missing routes to allowlist
- `backend/test/openapi.snapshot.test.ts`: Updated with dispute feature schema changes

## Acceptance Criteria Met

✅ **Data file permissions verified**: JSON stores restricted to owner-only (`0600`) in all code paths and deployment configs
✅ **No plaintext secrets persisted**: Secret-bearing fields are sanitized before any JSON write
✅ **Security documentation complete**: SECURITY.md reflects interim mitigation, risk assessment, and Postgres migration plan
✅ **All CI checks pass**: Backend test suite fully green (291 tests passing)

## Testing
- 16 security regression tests covering permissions, sanitization, backup/restore
- Full backend suite: 291 tests passing, 0 failures
- TypeScript compilation: No errors
- Manual verification of JSON file permissions in test environment

## Security Considerations
- This is an interim mitigation while the project transitions to Postgres-backed storage
- File-based persistence inherits OS-level security model; compromised hosts can still be breached
- Owner-only permissions + secret sanitization provide defense-in-depth for development/staging
- Production deployments should consider additional controls: encrypted filesystems, regular backups, audit logging

## Migration Path
The codebase is ready for the planned Postgres migration. When the database schema is complete:
1. Dual-write during transition period
2. One-time import of existing JSON data
3. Runtime cutover via configuration flags
4. Removal of file-backed store from default deployment
@vercel

vercel Bot commented Aug 29, 2026

Copy link
Copy Markdown

@Swayy713 is attempting to deploy a commit to the ritik4ever's projects Team on Vercel.

A member of the Team first needs to authorize it.

@drips-wave

drips-wave Bot commented Aug 29, 2026

Copy link
Copy Markdown

@Redsight51 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@github-actions github-actions Bot added documentation Improvements or additions to documentation backend labels Aug 29, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[SECURITY] Encrypt or restrict permissions on bounties.json data-at-rest

2 participants