Priority Fixes: What to Do First
Categories:
If you only read one page, read this one. It is ordered by risk removed divided by effort, which is not the same as severity order.
The roadmap deliberately separates two quantities that get blurred: how many findings a fix closes and how much risk it removes. They are not the same, and the first item on this list closes exactly one finding.
Every file and line target below was read at the pinned commit.
Tier 1: this week
| # | What, and where | Removes | Effort |
|---|---|---|---|
| 1 | Untrack the agent settings file and rotate the Cloudflare Access service token. git rm --cached PhenomApp/.claude/settings.local.json, add the path to .gitignore (no rule covers it today; git check-ignore -v exits 1), rotate in Cloudflare, revoke every certificate issued against the leaked signing request. |
The live limb of W-7, and possibly a Critical pending Q-1 | Minutes, plus one vendor conversation |
| 2 | Authenticate the MCP tool server. Add middleware before the route registration in phenom-infra/modules/chat-mcp-server/app/src/index.ts:64, :75. Done 2026-08-18 by PR #261, which deletes the deployment instead of authenticating it and adds a fail-closed bearer check; applied and probed in both environments. See MGR-C02. |
1 Critical (W-1). It does not remove a live public path, because the mutual-TLS listener bounds that today. It removes the estate’s dependence on that listener never changing. | Hours |
| 3 | Constrain the CI OIDC trust policy and narrow the same role’s secret reads, in one pull request. phenom-infra/modules/ci-cd/main.tf:21 and :103. |
2 High (W-3), and it breaks a Critical chain between a developer host and the AWS account | One Terraform condition plus one resource list |
| 4 | Remove the REJECTED sentinel passcode in phenom-drop. |
1 High (MGR-H13) | Tiny |
Why item 1 leads on cost, not severity
It is the only place in this assessment where the exposure is a live credential in a tracked file, the fix is two commands, and the question that would raise it to Critical is one read-only dashboard lookup you can perform yourselves.Tier 2: this quarter
| # | What, and where | Removes | Effort |
|---|---|---|---|
| 5 | Pin audience and issuer in the Hasura JWT config. phenom-infra/environments/production/secrets.tf:29-34. |
1 Medium, and it breaks a Critical chain’s third hop | One Terraform object, no application change |
| 6 | Stop mapping a dashboard-gate group to the engine’s reserved superuser role. environments/production/lambda-functions/hasura-cognito-trigger/index.js:121-122. |
1 High + 1 Medium (W-2), and it removes a Critical chain’s escalation path | One Lambda edit, plus deciding what role the dashboard needs |
| 7 | Add web/_headers to www scoped to /reset-password*, then delete the third-party analytics tag from that page. A new file in www, and www/web/reset-password/index.html:74. |
1 Medium, and it breaks a High chain (W-5) | One new file |
| 8 | Give development its own reset host. environments/development/locals.tf:31. |
1 Medium, and it removes the fan-in that makes W-5 estate-wide | One line plus a CI assertion |
| 9 | Measure the DMARC and DKIM posture, then act on the result. Neither underscore name was queried, so this assessment has no finding here and no recommendation follows from it yet. Query _dmarc.thephenom.app and a _domainkey selector. |
Closes Q-15. If DMARC is absent, publishing it bounds the social-engineering limb of W-5. If present, there is nothing to do. | Minutes to measure |
| 10 | Scope checkov to environments/ and pin the action to a SHA. phenom-infra/.github/workflows/prod-infra-ci.yml, dev-infra-ci.yml and chat-ci.yml. |
W-8, and it puts 42 files inside the gate | Hours, plus a baseline pass |
| 11 | Take the Hasura admin secret off the two Cloudflare Workers and define per-service roles. phenom-backend/admin_sandbox/nest-api, admin_sandbox/chat-edge-auth, and the Hasura metadata. |
RC-2’s 8 findings, and it caps the impact term on many more | Weeks. See the sizing warning below. |
Do not size item 11 as an edit
The work is creating named roles that do not exist, not narrowing an existing one. On the default source there is noadmin permission block to narrow, and the estate’s own convention rejects defining one as inconsistent. If you plan this as “tighten the admin role”, the estimate will be wrong by an order of magnitude.
Tier 3: multi-finding structural work
12. One session component
The largest single win, and the one most likely to be underestimated.
One missing component appears across seven repositories:
POST /auth/sessionaccepting a cross-site request with no Origin, Referer, CSRF-token or Content-Type check, in four places- No
__Host-cookie prefix, in three - No logout, or a logout defeated by a page reload, in three
- No revocation, in four
- Authenticated state surviving logout, in four client stores
One component with an origin assertion, a __Host--prefixed opaque session id, a revocation handle and a logout purge closes or bounds all of them. Effort is large. This is the RC-1 remedy rather than a patch per instance.
A counting caveat, stated so nobody re-derives it in a planning meeting. The source calls this nineteen findings; its five sub-counts add to eighteen. The set is real and its cardinality is 18 or 19 depending on a membership list neither artifact publishes. The remediation does not depend on which.
13. Replace filter: {} on the select blocks
Land the guardrail first and ship the mobile client before the server change. W-4 carries the ordering constraint and the re-escalation dependency, neither of which appeared in any prior roadmap.
14. Fill the org CI baseline
dot-github and dot-github-private each contain exactly one file. All 121 first-party action references across 9 repositories are mutable tags, including the scanner that gates PhenomApp pull requests and the checkov action that gates the production apply. Verified.
Filling that repository is the cheapest way to make one change reach 32 repositories, and it is the only item on this page that touches no product code.
Dependency graph
The orderings below are load-bearing. Getting one backwards costs time or breaks something in production.
PhenomApp token"] --> Z["W-7 credential lifecycle"] B["2. Authenticate
MCP tool server"] --> D["11. Per-service
Hasura roles"] D --> E["W-9 detection
and alerting"] Z --> E F["13a. CI assertion:
no empty filter"] --> G["13b. Ship mobile client"] G --> H["13c. Replace the 47
filter: {} blocks"] H --> I["Re-rate MGR-L33
(escalates)"] J["10. Move event-trigger
webhooks to zone host"] --> K["Set workers_dev = false"] L["6. Fix Cognito group
to role mapping"] --> M["MGR-H10: give moderator
role its update permission"]
Read the graph as four hard rules:
- Detection comes last, not first. Alerting on a shared superuser secret cannot attribute anything. Do W-1 and per-service identities before you build W-9.
- The mobile client ships before the Hasura permission change. Five PhenomApp queries depend on the over-fetch.
- Webhooks move to a zone hostname before
workers_dev = false. Reversing it breaks the scheduled workflow. - The moderator role gets its update permission at the same time as the superuser mapping is fixed. Otherwise you have moved the problem rather than removed it, and staff will find a new way around.
Before you action any of this
Two remediation steps in the source material are wrong as written and will cost you time: one names a Route 53 zone that does not exist, and one claims a WAF change will not strand a deploy when it will. Neither has been identified to a specific item on this page. Verify against the live account before you act. See Provenance and handling.
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.