Security hardening, duplicated-logic cleanup, and doc updates - #5
Merged
Conversation
Security:
- Gate the whole app (setup wizard included) behind Microsoft Entra ID
sign-in via Azure App Service Authentication ("Easy Auth" v2), enforced
at the platform level. Previously the app had no authentication layer at
all -- anyone who could reach the URL had full read/write access,
including the ability to rotate the Graph client secret. This was
already flagged as the top accepted gap (NFR-SEC-5) in the technical
spec; it's now closed by default (enableEntraIdAuth = true).
- Add SecurityHeadersMiddleware: a strict per-request-nonce Content-
Security-Policy, X-Content-Type-Options, X-Frame-Options, Referrer-
Policy, Permissions-Policy, and suppress Kestrel's Server header.
- Harden the DMARC XML parser against XXE/entity-expansion by explicitly
prohibiting DTD processing and nulling the XmlResolver, rather than
relying on .NET's implicit (already-safe) defaults.
- Cap zip/gzip attachment decompression at 50 MB of actual bytes copied
(not the archive's declared, attacker-controlled size) -- the shared
mailbox accepts attachments from arbitrary internet senders, so a
decompression bomb is real attack surface, not theoretical.
- Add tests for all three new guards (DOCTYPE rejection, zip/gzip
decompression limits).
Duplicated-logic cleanup (found via a dedicated review pass):
- Add DmarcAlignment.IsAlignedPass as the single source of truth for the
"aligned pass" rule, previously reimplemented separately in the
ingestion pipeline, the chart API, and the dashboard summary.
- Reference the existing SenderLegitimacyEvaluator.VerifiedAlignedPassRatioThreshold
constant from the dashboard's badge instead of a disconnected magic 95.
- Add DbContext.GetOrCreateSingletonAsync to remove the repeated
"FindAsync -> null check -> new -> conditionally Add" ceremony
duplicated across the Setup wizard's singleton-settings pages.
Docs:
- Bump the technical specification to v1.4: new NFR-SEC-5 (Easy Auth),
NFR-SEC-7-9 (headers/XXE/decompression-bomb), updated test counts and
verification evidence (including a headless-browser CSP/nonce check).
- Rework docs/deployment.md with a Mermaid flow diagram covering the full
deployment journey (Entra ID app registrations -> GitHub config ->
deploy workflow -> first-run setup wizard) and a step-by-step Easy Auth
setup section.
- Add a README Security section and update test-count references.
All 65 tests pass; dotnet format --verify-no-changes is clean; both
Bicep templates compile with 0 errors/0 warnings (validated with the
Bicep CLI); the CSP/nonce change was verified against a running instance
via a headless-browser pass with zero console errors.
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A full security review of the repository, a pass to consolidate duplicated logic, source comments on the non-obvious parts, and updated documentation (including a new deployment flow diagram).
Security
NFR-SEC-5) in the technical spec. It's now closed by gating the whole app behind Microsoft Entra ID sign-in via Azure App Service Authentication ("Easy Auth" v2), enforced at the platform level — no application code involved, on by default (enableEntraIdAuth = trueininfra/main.bicep).SecurityHeadersMiddleware: a strict, per-request-nonce Content-Security-Policy (default-src 'self', nothing loaded from a CDN — everything underwwwroot/libis vendored),X-Content-Type-Options,X-Frame-Options,Referrer-Policy,Permissions-Policy, and the KestrelServerheader suppressed.XmlResolverbefore parsing, rather than relying on .NET's implicit (already-safe) defaults — reporting organizations are untrusted third parties on the internet.Duplicated-logic cleanup
Found via a dedicated review pass:
DmarcAlignment.IsAlignedPass— single source of truth for the "aligned pass" rule, previously reimplemented separately in the ingestion pipeline, the chart API, and the dashboard summary.SenderLegitimacyEvaluator.VerifiedAlignedPassRatioThresholdconstant instead of a disconnected magic95.DbContext.GetOrCreateSingletonAsyncremoves the repeated "FindAsync → null check → new → conditionally Add" ceremony duplicated across the Setup wizard's singleton-settings pages.Docs
NFR-SEC-5rewritten (Easy Auth), newNFR-SEC-7–9(headers/XXE/decompression-bomb), updated test counts and verification evidence.docs/deployment.mdreworked with a Mermaid flow diagram covering the full deployment journey (Entra ID app registrations → GitHub config → deploy workflow → first-run setup wizard) and a step-by-step Easy Auth setup section — the three app registrations involved are easy to conflate, so the diagram and an explicit table spell out which is which.Test plan
dotnet build -c Release— 0 warnings, 0 errorsdotnet format --verify-no-changes— cleandotnet test— 65/65 passing (62 previous + 3 new security-guard tests)authsettingsV2resource)<script>) still renders correctly under the new nonce-based CSP with zero console errorsinfra/)Generated by Claude Code