Engineering Log
We're Automating CMMC 2.0 Hardening — and We Won't Trust It Until Our Own Box Survives It
ScopeHunter tracks CMMC 2.0 maturity for its users. Here's what building real automation for it actually looks like, including the part where we run it against ourselves first.
Scope: what this covers, and what it doesn't
Two different things get run together in this space, and they have opposite data-handling answers, so both are worth being blunt about before anything else.
The hardening automation runs on your infrastructure. It's a Salt formula applied to your own systems. By default it doesn't call home, and ScopeHunter never sees what lives on those boxes — so nothing stops you running it on hosts that sit inside a CUI enclave.
Reporting results back to us is opt-in, and off by default. We're building the other half of this now: letting the formula send its check results here, so evidence updates itself instead of someone re-typing it. That switch stays off unless you turn it on — the paragraph above is a commitment, not a description of a version that happens to predate the feature. Enabled, what leaves the host is a list of check identifiers, each with a pass, fail, or skipped result. Worth knowing before you turn it on inside an enclave: each result carries a detail string from the check's own output, which can name a port, a path, a service, or an account. That isn't CUI, but on a system that holds CUI it is still a description of that system's security posture, and it deserves a deliberate decision rather than a default.
The boundary rule this rests on, stated plainly: a system assessed at CMMC Level 2 may transmit CUI only to another system authorized to protect it at Level 2 or higher. Sending CUI — or data that describes a CUI system's security configuration — to a system that hasn't been assessed to that standard (a commercial SaaS, a lower-tier or non-CMMC system, anything outside your authorization boundary) is a spillage, not a shortcut. ScopeHunter is commercial-scope and sits outside any CUI boundary — which is exactly why reporting is off by default and why we spell out what the detail string can contain. The moment a Level 2 host reports here, data is leaving your assessed boundary, and it is on you to ensure nothing in that stream is CUI. We hold none and the design keeps it that way, but honoring the boundary is your call to make deliberately, which is why the switch is yours and starts off.
ScopeHunter itself is commercial-scope and holds compliance metadata only. ScopeHunter is not an authorized system for storing actual Controlled Unclassified Information (CUI) or Federal Contract Information (FCI). Use this tool to document and track your compliance program — never enter actual CUI, FCI, or other controlled content into any field here. That isn't only a request: every compliance surface in the product is gated behind a one-time, org-level attestation, and answering "yes, we need to store real CUI or FCI here" is a hard stop rather than a warning you can dismiss. Your tracking can still live with us; the controlled content has to stay in a separately authorized system.
And on the certification question, since it's the one most often blurred: this is hardening automation and program tracking, not a path to a certificate. CMMC Level 2 certification is awarded after an assessment by an authorized C3PAO, against your system and your SSP. Nothing here substitutes for that — a distinction worth confirming with any tool you evaluate, ours among them.
If you've used ScopeHunter's Compliance tools to track CMMC 2.0 or SOC 2 milestones (preview the workspace — controls, tests, evidence, and policies in one place), you already know the gap we're talking about here: it's easy to track that a control needs to be met, and much harder to actually enforce it on a real box. So a sister project — an infrastructure-hardening Salt formula covering the OS-enforceable subset of NIST SP 800-171, the requirements underneath CMMC Level 2's technical practices — has been getting built out, and we're documenting the process honestly, the same way we label our own feature maturity on the status page: what's live, what's staged, and what's deliberately not turned on yet.
Not every control is code's job
Of NIST SP 800-171's 110 requirements, roughly half are organizational — personnel screening, physical security, written incident response plans — and staple exactly zero lines of Salt to anything. We use the same three honest labels our own compliance tracking uses internally for this:
Of those 110 requirements, 47 are enforceable at the operating-system layer. All 47 have a real Salt state behind them — not most of them, and not approximately: the formula's own test suite fails the build if a requirement its control map calls automatable has no state implementing it. The other 63 are organizational and are labeled Manual, not folded into a percentage. We used to publish a figure here instead ("~95% of the automatable subset"). It was a hand estimate, it was wrong in both directions, and it was exactly the kind of number this page criticizes elsewhere. Counts you can recompute from the control maps are harder to round.
Three operating systems have had the formula genuinely applied, which is a different claim from rendering cleanly against them:
- Debian 13 — two live production hosts, one of them serving this page.
- Rocky Linux 9.8 (Red Hat family) — first full apply on 2026-08-10. It found eight defects that static checking could not see, including a control that failed on every Red Hat host because it matched a commented-out line in the stock sudoers file.
- Windows Server 2022 — Level 1 and all eight Level 2 families, validated on a real host with each control broken on purpose to confirm it notices.
Three things are built but not validated, and we would rather say so than let the list above imply them: Windows workstations (implemented, never run on a real client OS), domain-joined Windows (controls owned by Group Policy deliberately refuse to apply locally, and the verify-only paths are unwritten), and Ubuntu (same package family as Debian, not separately exercised — we listed it here before, on the strength of family resemblance rather than a run).
We run it on our own box before we ship it to anyone else
First, the model, since it's the whole point: this is automation you run on your own gear. We ship the Salt formula; you apply it inside your own boundary, under your own IAM, on your own schedule. We never run it on your systems and never reach into them — the same posture as the "doesn't call home" commitment above.
What we do run it on is ourselves. The formula is applied against two real, live systems today — one of them is the box serving this page right now. Not a lab VM built for a demo: real production infrastructure, with our own SSH access, our own IAM, our own uptime on the line.
That's not a marketing detail — it's how the bugs actually got caught: a wrong package name for a password-quality tool on Debian, a stale firewall rule that would have quietly left a port exposed after a "fix," a false positive against a cloud provider's own managed sudo configuration. Small, boring bugs, individually. The kind that pass code review and fail in production. Every one of them got caught on our box first, instead of surfacing in your environment after you'd already trusted it.
The control we refused to ship on a guess
The single highest-risk change in the whole formula is also one of the simplest-sounding requirements: limit failed login attempts. On one OS family, the standard way to wire that in touches a PAM authentication stack's own internal control-flow logic. Get one number wrong there and the failure mode isn't "attackers get one more try" — it's every login, including root's, denied at once, on every service that uses that stack.
We wouldn't ship that from documentation and hope. Instead, we found the actual system tool responsible for composing that stack safely, patched a copy of it to run against scratch, throwaway directories — never a live system's real configuration — and used it to prove, not assume: a correct password reaches the accept path, an incorrect one is denied immediately, and removing the change cleanly reverts to the original stack. Multi-factor authentication for privileged access got the same treatment: fully built, deliberately left switched off behind an explicit two-stage flag until every account is actually enrolled and a non-SSH recovery path is confirmed open.
Neither is enabled in enforcement mode on our own production boxes yet, on purpose. Staged and verified isn't the same claim as "flipped on everywhere," and we're not going to blur that distinction just because the code is done.
Why this matters if you're the one being assessed
A compliance report that can't verify something from inside a system — MFA enforced by your cloud provider's identity layer instead of the OS, say — shouldn't quietly mark it "met" either. The honest move is to say exactly what was checked, flag what wasn't, and point at where the rest of the evidence actually has to live: your SSP, with real proof behind it. That's the same standard ScopeHunter holds its own feature list to, and it's the standard this formula is being held to before it's trusted with anyone else's audit.
That holds whether you're a contractor preparing for a C3PAO assessment or a commercial organization adopting 800-171 as a security baseline with no CUI obligation at all. The technical work is the same either way — the same accounts locked down, the same logging, the same firewall posture. What differs is the evidence burden and who eventually checks it. A good deal of what gets sold as "CMMC compliance" is really just competent Linux hardening with a certificate stapled to the end, and it's worth knowing which half you're buying.