4.6 KiB
4.6 KiB
M014 Security Remediation Verification
This report retests the two confirmed findings from M013 after code fixes landed in M014.
Related assessment:
docs/security-assessments/M013-adversarial-security-assessment.md
Fixed Findings
1. Job import preview SSRF via hostname-based loopback/private-address bypass
- Original issue:
POST /api/jobimport/previewaccepted hostnames that resolved to loopback/private addresses and fetched internal targets. - Fix status: Fixed
- Primary code changes:
JobTrackerApi/Services/JobImport/JobImportService.csJobTrackerApi/Services/JobImport/IHostAddressResolver.csJobTrackerApi/Program.cs
What changed
- URL validation now resolves hostnames before allowing outbound fetches.
- Validation rejects loopback, private, link-local, and other internal destinations for both literal IPs and resolved hostnames.
- Automatic redirects are disabled on the
jobimportHTTP client.
Retest inputs and outcomes
| Exploit input | Expected after fix | Observed |
|---|---|---|
http://127.0.0.1.nip.io:5202/api/auth/config |
reject | 400 with parser none and local/private-network rejection |
http://localhost.localdomain:5202/api/auth/config |
reject | 400 with parser none and local/private-network rejection |
http://[::1]:5202/api/auth/config |
reject | 400 with local/private-network rejection |
http://2130706433:5202/api/auth/config |
reject | 400 with local/private-network rejection |
https://example.com |
allow public fetch path | request reached parser path and failed only with No JobPosting schema found. |
Verdict
Pass. The original SSRF exploit shapes are now blocked and a normal external URL still follows the intended public-host path.
2. Subjectless signed local JWTs authenticate successfully and can disable owner scoping
- Original issue: a validly signed local JWT without
nameidentifier/subwas accepted, and owner filters were written to allow all rows whenCurrentUserIdwas null. - Fix status: Fixed
- Primary code changes:
JobTrackerApi/Services/LocalAuthIdentity.csJobTrackerApi/Services/CurrentUserService.csJobTrackerApi/Program.csData/JobTrackerContext.cs
What changed
- Local JWT bearer validation now rejects tokens without a concrete subject/nameidentifier.
- Current-user resolution uses the same required-identity rule.
- Owner query filters now deny on null current user instead of allowing all rows.
Retest input and outcomes
Malformed token shape reused from M013:
- valid local signature
- valid issuer/audience/lifetime
- missing
ClaimTypes.NameIdentifier/sub
Observed after fix:
| Request | Expected after fix | Observed |
|---|---|---|
GET /api/auth/me with subjectless signed local JWT |
reject | 401 |
GET /api/companies with subjectless signed local JWT |
reject | 401 |
GET /api/rules with subjectless signed local JWT |
reject | 401 |
Automated proof
Focused tests now cover:
- required-subject local identity behavior
- fail-closed owner query filters when current user is missing
Verdict
Pass. The malformed token no longer authenticates, and the owner filters fail closed behind the auth boundary.
Focused Test Evidence
SSRF-focused tests
dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --filter JobImportServiceTests
Observed:
- passed
- covers loopback-resolving hostname rejection
- covers private-address hostname rejection
- covers normal public-host path
Local-auth / owner-scope tests
dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --filter "LocalAuthIdentityTests|AuthAndSystemControllerTests|OwnershipGuardTests"
Observed:
- passed
- covers required-subject behavior and fail-closed owner filter semantics
Remaining Boundaries
- The local runtime still uses a partial SQLite schema for some domain tables, so broader cross-user raw-id authorization retests remain best treated as a separate follow-up pass in a fuller environment.
- Those unresolved candidates were not needed to close the two confirmed
M013findings, because both confirmed exploit shapes were retested directly and now fail.
Final Verdict
M014 closes the two confirmed M013 vulnerabilities:
- hostname-based authenticated SSRF in job import preview — fixed
- subjectless local JWT authentication / owner-scope fail-open behavior — fixed
Both fixes were verified with focused automated tests and hostile runtime retests using the original exploit shapes.