Skip to content

docs(dnn): #131 machineKey rotation+scrub runbook + DNN10 migration readiness - #854

Merged
jsboige merged 1 commit into
masterfrom
docs/dnn-machinekey-scrub-runbook
Jul 23, 2026
Merged

docs(dnn): #131 machineKey rotation+scrub runbook + DNN10 migration readiness#854
jsboige merged 1 commit into
masterfrom
docs/dnn-machinekey-scrub-runbook

Conversation

@jsboige

@jsboige jsboige commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Scope

Dispatch ai-01 msg-20260722T224852-6cz88c (primaire + secondaire). The machineKey runbook is the highest-severity item in the DNN lane.

Files

docs/dnn/machinekey-rotation-scrub-runbook.md (primaire — HIGH severity, gated jsboige)

The DNN machineKey is exposed publicly on branch dnn/sandbox-runtime-1032 (commit 4b0297ee). Treat as compromised.

SECRET-SAFE: references secrets by location only (file path DNNPlatform/web.config<system.web><machineKey> attributes validationKey/decryptionKey). Zero key value in the doc. GitGuardian passes (matches #842/#851 discipline). Pre-commit secret-scan of the doc: 0 real-key fragments, 0 long-hex strings.

Procedure (copy-paste at GO jsboige):

  • (A) Rotation server-side = the ONLY real fix (do FIRST). PowerShell snippet generates fresh material via Get-Random (does NOT print old keys). Recycle app pool → invalidates old cookies/ViewState (pre-go-live = near-zero cost, do before public launch).
  • (B) Scrub repo (AFTER rotation): B1 bleed-stop (delete remote ref) recommended; B2 history-rewrite gated #415. Both are NOT purge (GitHub retains orphan commits server-side) → rotation A is remediation, scrub is hygiene. Branch dnn/sandbox-runtime-1032 is load-bearing (migration ref) → scrub AFTER rotation + AFTER readiness-doc capture.
  • (C) Verify: master placeholder unchanged, ref gone, live on new keys, pre-commit guard (chore(security): #131 Phase D — pre-commit guard against web.config secret leak #842) active.
  • Mandatory ordering: A → B1 → C.

docs/dnn/dnn10-migration-readiness.md (secondaire — durable, read-only)

Consolidates ticks 29-31 findings (survive dashboard condensation):

  • Versions measured DLL-level (DNN 10.3.2.0, 2sxc 21.07.00, .NET Framework 4.8).
  • Telerik migration surface = ZERO (0/206 DLLs, Telerik.Web.UI.dll absent, 0 .ascx) — the usual DNN 10 blocker is already cleared.
  • Skin objects DNN 10 standard (26 .ascx), Razor APIs stable (TabInfo/PortalSettings.ActiveTab not deprecated).
  • OpenStore Telerik-free (6 DLLs). Residual items gated (runtime smoke-test, skin tabid=138, machineKey, [DNN i18n portage · 1/6] Portal / 2sxc App export — hard unblocker (jsboige) #681) — none block v0.9.0 tag (Opt 1).

Constraints honored

  • Staged / ZERO execution of gated-ops.
  • Secret-safe (no key value committed).
  • Branche feature + PR, verdict QA = ai-01.
  • 0 prod CSV (gel T&A).

jsboige decisions referenced (not resolved by this PR)

🤖 Worker po-2023

…eadiness

machinekey-rotation-scrub-runbook.md (HIGH severity, gated jsboige):
- machineKey EXPOSED on public branch dnn/sandbox-runtime-1032 (commit 4b0297e)
- SECRET-SAFE: references by location only (file path + attribute name), zero
  key value in the doc. GitGuardian passes.
- (A) Rotation server-side = the ONLY real fix (do first); PowerShell snippet
  GENERATES fresh material via Get-Random (does not print old keys); recycle
  app pool invalidates old cookies/ViewState (pre-go-live = near-zero cost).
- (B) Scrub repo: B1 bleed-stop (delete remote ref) recommended; B2 history-
  rewrite gated #415. Both NOT purge (GitHub retains orphans) so rotation A
  is remediation, scrub is hygiene. Branch load-bearing = scrub AFTER rotation
  + AFTER readiness doc capture.
- (C) Post-action verify: master placeholder, ref gone, live on new keys.
- Ordering mandatory: A -> B1 -> C.

dnn10-migration-readiness.md (durable, consolidates ticks 29-31):
- Versions measured DLL-level (DNN 10.3.2.0, 2sxc 21.07.00, net48).
- Telerik migration surface = ZERO (0/206 DLLs, Telerik.Web.UI.dll absent, 0
  .ascx) - the usual DNN 10 blocker is already cleared.
- Skin objects DNN 10 standard (26 .ascx), Razor APIs stable (TabInfo/
  PortalSettings.ActiveTab not deprecated).
- OpenStore Telerik-free (6 DLLs). Residual items gated (runtime smoke-test,
  skin tabid=138, machineKey, #681) - none block v0.9.0 tag.

Dispatch ai-01 msg-20260722T224852-6cz88c (primaire + secondaire).
Staged / ZERO execution of gated-ops. No key value committed.

Co-Authored-By: Claude-Code <noreply@anthropic.com>
@jsboige
jsboige merged commit 82a1e02 into master Jul 23, 2026
3 checks passed
@jsboige
jsboige deleted the docs/dnn-machinekey-scrub-runbook branch July 23, 2026 02:45
jsboige added a commit that referenced this pull request Jul 23, 2026
…ok (#856)

Transforms scattered staged docs (#854 machineKey + #442 web.config hardening +
dnn10-migration-readiness + skin diagnostic #851) into ONE top-to-bottom
procedure jsboige executes on go-live day.

- Block-head: 4 blocking arbitrages checklist (machineKey rotation / skin
  tabid=138 Opt 1 vs 2 / #681 2sxc export / T&A #802).
- Body: canonical ordered sequence (A rotation server-side FIRST -> B1 scrub
  bleed-stop after rotation -> C verify #442 hardening already-merged -> D
  DNN10 readiness -> E 2sxc #681 -> F deploy #132 + ai-01 live verdict).
- Every step tagged [jsboige-DECISION] / [po-2023-EXEC] / [ai-01-VERDICT].
- Each step POINTS to its staged doc (does not duplicate content).
- #811 dependabot assessment folded in (transitive, reco merge, 0 prod path).
- SECRET-SAFE: references by location only (0 key/password/CS value).
  GitGuardian must pass.

Note (code=truth): #442 = MERGED (hardening on master, not HELD), #444/#132
= CLOSED - capstone reflects reality.

Dispatch ai-01 msg-20260723T024927-zwcvck (primaire). Staged / 0 exec gated.
Verdict go-live = ai-01.

Co-authored-by: Claude-Code <noreply@anthropic.com>
jsboige added a commit that referenced this pull request Jul 25, 2026
* chore(dnn): persist ACME challenge web.config bypass (win-acme renew)

The .well-known/acme-challenge/web.config (383 B, StaticFileModule +
mimeMap, no handlers/DNN pipeline) was already ACTIVE in live — tested
2026-07-01: https://dnn.argumentum.myia.io/.well-known/acme-challenge/x
returns HTTP 404.0 IIS brut (served before DNN, functional for win-acme).

Persisting it on the runtime branch so the win-acme certificate renewal
(2026-08-23) stays non-blocked across redeploys.

ai-01: GO commit on runtime branch.

Co-Authored-By: Claude-Code <noreply@anthropic.com>

* docs(dnn): document ACME bypass mechanism + B1 two-commit disposition (#854)

The win-acme HTTP-01 bypass was recorded on master only as a status line
("ACME bypass active in live, renew 2026-08-23") — the *mechanism* was
undocumented and existed solely on branch dnn/sandbox-runtime-1032
(commit 78cd1aa), which B1 deletes.

- go-live-turnkey-checklist.md: document the scoped child web.config
  (StaticFileModule handler + extensionless mimeMap) and why DNN needs it,
  point at the now-tracked file, mark the runtime branch deleted.
- machinekey-rotation-scrub-runbook.md: record that the branch carried TWO
  unique commits with distinct dispositions (4b0297e discarded by design,
  78cd1aa preserved), and generalise the pre-delete enumeration rule.

No secrets: the ACME file contains no key material; master's web.config
machineKey placeholders (7-char REPLACE) are untouched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude-Code <noreply@anthropic.com>
@myia-ai-01

Copy link
Copy Markdown

B1 executed and verified — with a preservation step the runbook did not anticipate

Rotation A is live (po-2023 firsthand report, msg-20260725T130401-at8iuf): new key in the live web.config of dnn.argumentum.myia.io (site id:52, full IIS on po-2023, physicalPath D:\Dev\Argumentum\DNNPlatform), CHANGED: True on both attributes, algorithms preserved, site UP (HTTP 302, 0.38 s), 0 "Validation of viewstate MAC failed", and 0 key values in any report, stdout, or commit. Explicit Restart-WebAppPool remains pending (non-elevated shell); the standard IIS auto-recycle on web.config change almost certainly applied. B1 does not depend on that — see below.

⚠ The runbook's load-bearing warning was incomplete

B. warned only about the bin/ migration reference. But git log --oneline origin/master..origin/dnn/sandbox-runtime-1032 showed two unique commits:

Commit Content Disposition
4b0297ee sandbox runtime snapshot 10.3.2 + 2sxc 21.07 (3338 files) — carries the exposed machineKey discarded by design; analysis captured in dnn10-migration-readiness.md, canonical realigned bin/ held locally by po-2023
78cd1aab DNNPlatform/.well-known/acme-challenge/web.config (12 lines, zero secrets) — win-acme HTTP-01 bypass preserved to master first (PR #897, 05f54ee8)

The ACME bypass is load-bearing for certificate renewal: cert 9D80D4CC expires 2026-09-27, renewal due 2026-08-23 (~4 weeks). Master recorded only the status ("ACME bypass active in live") — never the mechanism; grep -rn "ACME_StaticFile\|StaticFileModule" docs/ returned nothing. Deleting the branch first would have destroyed the only copy, and a box rebuild would have broken renewal with no trace of why. #897 cherry-picks the file (original authorship preserved) and documents the mechanism in go-live-turnkey-checklist.md; the runbook now records the two-commit disposition rule.

Pre-delete scan — the leak was confined to that one ref

Checked all 29 remote branches for real key material (value lengths only, never values):

  • dnn/sandbox-runtime-1032: validationKey len 128REAL
  • all 28 others (incl. master): len 7REPLACE placeholder

So B1 addressed the entire git-side exposure; nothing else carried it.

Execution + verification (runbook §C)

$ git push origin --delete dnn/sandbox-runtime-1032
 - [deleted]           dnn/sandbox-runtime-1032

C.2  git ls-remote origin dnn/sandbox-runtime-1032  → empty                    ✅
C.1  master web.config validationKey value length   → 7 (REPLACE, untouched)   ✅
     DNNPlatform/.well-known/acme-challenge/web.config on master → present     ✅
C.4  no other remote ref carries real key material                             ✅
C.5  .githooks/pre-commit (#842) active — gates the exact path
     DNNPlatform/web.config; not bypassed (no --no-verify used)                 ✅

Honest scope of what B1 achieved

Per the runbook's own framing: this is a bleed-stop, not a purge. 4b0297ee remains retrievable by SHA server-side for some time, and any clone/fork that fetched it still has it. Rotation (A) is the remediation — and it is done. B1 removes trivial discoverability via branch listing.

Remaining, both for jsboige:

  1. Restart-WebAppPool -Name "dnn.argumentum.myia.io" for 100% certainty the new key is in w3wp memory (needs elevation; po-2023's shell was non-elevated).
  2. B.2 history rewrite — still gated by chore(repo): réduire le poids du dépôt (.git 2,2 GB) — binaires de build commités dans l'historique #415 and, per the runbook's own recommendation, low marginal value given server-side retention. My read: not worth the force-push risk on a shared public repo. No action taken.

Procedural note for the record: po-2023 flagged, unprompted, that they mutated before the firsthand verify I had set as PRIMARY, having read "sandbox" as the local IIS Express :8090. The target turned out to be the internet-facing site. The outcome was clean and secret-safe, and the self-report is what let this issue be closed accurately rather than on a wrong premise — but the verify-before-mutate ordering exists precisely because the blast radius isn't knowable until you check.

🤖 Coordinator ai-01

jsboige added a commit that referenced this pull request Jul 25, 2026
…nbook (#907)

The runbook's threat model said the prod site "is the target IF it runs the
exposed key" and left that untested. web1 classified the live prod web.config
(lengths + algorithm names only, ZERO values transmitted) and the answer is
categorical: all four attributes differ from the exposed sandbox key.

  exposed (4b0297e): validationKey 128 hex / decryptionKey 64 hex / HMACSHA256 / AES
  prod web1:          validationKey 40 chars / decryptionKey 48 chars / SHA1 / 3DES

40/48 + 3DES/SHA1 is the legacy ASP.NET shape (20 bytes for SHA1, 24 for 3DES);
the sandbox used the modern shape. Prod cannot be running the exposed key.

=> Prod is OUT OF SCOPE of the compromise remediation. No emergency rotation,
no session invalidation on argumentum.games. The 2026-07-24 jsboige GO covered
the SANDBOX (po-2023 box, genuinely leaked live); extending it to an
outward-facing prod action would have been unjustified and, as measured,
unnecessary.

Records separately (NOT merged into the incident) that SHA1/3DES are legacy
algorithms: a hardening item for a normal maintenance window with explicit
sign-off, backlog only, not executed.

Method note kept in the doc: non-identity was proven WITHOUT any secret
crossing a wire. Compare fingerprints, never values.

Refs #131 #854

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants