Files
jobtrackingapp/docs/security-assessments/M015-authorization-replay-report.md
T

4.1 KiB
Raw Blame History

M015 Cross-User Authorization Replay Report

This report covers the follow-up tenant-boundary work after M013 and M014.

Related artifacts:

  • docs/security-assessments/M013-adversarial-security-assessment.md
  • docs/security-assessments/M014-security-remediation-verification.md
  • docs/security-assessments/M015-hostile-fixture-setup.md
  • docs/security-assessments/M015-hostile-fixture-setup.json
  • docs/security-assessments/M015-s02-probe-results.json

Test Setup

A dedicated hostile-test SQLite database was created from the current EF model because the default development DB was missing core domain tables needed for real authorization probes.

Fixture runtime:

  • clean SQLite DB under .tmp/m015-fixture
  • API started with Data__Root=/home/pi/development/JobTracker/.tmp/m015-fixture
  • registration temporarily enabled for the fixture runtime
  • two real local users created through the API:
    • alice.m015@example.com
    • bob.m015@example.com

Alice-owned fixture resources created through the real API:

  • company_id = 1
  • job_id = 1
  • correspondence_id = 1
  • attachment_id = 1

All mutating requests used the real cookie + CSRF contract.

Cross-User Probe Summary

Bob targeted Alices fixture ids with a real authenticated session.

Defended in this pass

The following probes failed closed with 404 when Bob targeted Alices resources:

  • GET /api/attachments/1
  • GET /api/attachments/download/1
  • PATCH /api/attachments/1
  • DELETE /api/attachments/1
  • GET /api/correspondence/1
  • DELETE /api/correspondence/1
  • GET /api/jobapplications/1
  • PUT /api/jobapplications/1
  • PATCH /api/jobapplications/1/followup
  • GET /api/jobapplications/1/timeline
  • GET /api/jobapplications/1/tailored-cv-draft
  • GET /api/jobapplications/1/followup-draft

These routes did not expose or mutate Alice-owned data in this hostile fixture pass.

Confirmed Finding

Cross-user read leak on job history

  • Category: Authorization / data exposure
  • Endpoint: GET /api/jobapplications/{id}/history
  • Risk: Medium

Vulnerability

Before the fix, Bob could request Alices job history by raw job id and receive Alices JobEvent rows.

Observed pre-fix response:

  • GET /api/jobapplications/1/history as Bob
  • 200 OK
  • payload included Alice-owned event data, including the Created event for Alices job

Example exploit input

GET /api/jobapplications/1/history
Cookie: jobtracker_auth=<bob session cookie>

Root cause

Two issues combined:

  1. GetHistory(...) queried JobEvents directly by JobApplicationId without verifying that the parent job belonged to the current user.
  2. JobEvent had no owner-scoped query filter in Data/JobTrackerContext.cs.

Fix

  • GetHistory(...) now checks whether the requested job exists in the current users scoped JobApplications query and returns 404 if it does not.
  • JobEvent now has an owner-scoped query filter tied to JobApplication.OwnerUserId.
  • Added focused regression test:
    • JobTrackerApi.Tests/JobApplicationsAuthorizationTests.cs

Replay after fix

Observed post-fix response:

  • GET /api/jobapplications/1/history as Bob
  • 404 Not Found

Verdict

Fixed.

Automated Evidence

Focused regression test

dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --filter JobApplicationsAuthorizationTests

Observed:

  • passed
  • verifies GetHistory returns NotFound for another users job

Final Assessment

For the prioritized raw-id authorization seams exercised in this milestone:

  • confirmed and fixed: GET /api/jobapplications/{id}/history
  • no finding in this fixture pass: attachments, correspondence, primary job read/update, follow-up patch, timeline, tailored draft, follow-up draft

Remaining Boundary

This report covers the endpoints actually exercised in the hostile fixture pass. It does not claim that every authorization-sensitive route in the application has been exhaustively proven safe; it closes the high-risk raw-id seams prioritized from the earlier assessment with a real two-user runtime and replay evidence.