7 Proven Steps for CMMC Level 2 Remediation (2025)

Why this matters now

CMMC Level 2 is entering phased rollout in 2025. The winners will be teams that fix fast, collect evidence as they go, and make their configurations ODP-ready—so assessors can see that your policies and technical settings actually match what you’ve defined. This guide gives you a hands-on, code-heavy approach to get there with an 800-171r3 + ODP lens and an audit-grade evidence trail your C3PAO reviewer can follow.

7 Proven Steps for CMMC Level 2 Remediation (2025)

Looking for a fast path to board reporting? Read our NIST CSF 2.0 14-Day Board-Ready Metrics Plan!

Quick start: Run an external exposure sweep with our Website Vulnerability Scanner Online Free, then convert exploitable items into Level-2 backlog tickets.


What “ODP-ready” really means (in practice)

Organizationally Defined Parameters (ODPs) are your chosen values for controls (e.g., session timeout = 15 minutes; log retention = 365 days). “ODP-ready” means:

  1. You’ve chosen concrete values that fit your risk profile.
  2. Your configs/code enforce those values.
  3. You’ve captured artifacts—configs, PRs, deployment logs, SIEM settings, and retest screenshots—to prove it.

Below are 7 proven steps to apply ODPs, map to 800-171r3, and produce C3PAO-friendly evidence.


Step 1 — Declare your ODPs (source of truth)

Create a single, version-controlled file to anchor your parameters.

# odps.yaml (NIST 800-171r3 flavored)
session:
  idle_timeout_seconds: 900        # AC-12-ish parameter (example)
  absolute_timeout_minutes: 480
auth:
  jwt_exp_minutes: 15
  mfa_required: true
logging:
  retention_days: 365
  time_sync: 'NTP: pool.ntp.org'
network:
  tls_min_version: '1.2'
  hsts_max_age_seconds: 31536000
backups:
  frequency_hours: 24
  retention_days: 30
user_access:
  review_frequency_days: 90
  disable_inactive_days: 30

Tip: Reference this file from policy, IaC, pipelines, and acceptance tests so a single change updates everything consistently.


Step 2 — Enforce session timeouts everywhere

Windows (machine inactivity limit)

# Run as admin: set 15-minute inactivity logoff
New-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" -Force | Out-Null
New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" `
  -Name "InactivityTimeoutSecs" -PropertyType DWord -Value 900 -Force | Out-Null
gpupdate /force

Linux shells (auto-logout on idle)

# /etc/profile.d/odps.sh
export TMOUT=900
readonly TMOUT

SSH idle timeout

# /etc/ssh/sshd_config
ClientAliveInterval 300
ClientAliveCountMax 3   # 5 min * 3 = 15 min
systemctl restart sshd

Web app (JWT expiry, Node.js/Express)

// ODP: jwt_exp_minutes = 15
const jwt = require("jsonwebtoken");
const exp = Math.floor(Date.now() / 1000) + (15 * 60);
const token = jwt.sign({ sub: user.id, exp }, process.env.JWT_SECRET, { algorithm: "HS256" });

Step 3 — Make log retention & time sync provable

AWS CloudTrail + S3 lifecycle (Terraform)

variable "retention_days" { default = 365 }

resource "aws_s3_bucket_lifecycle_configuration" "logs" {
  bucket = aws_s3_bucket.trail_logs.id
  rule {
    id     = "trail-retention"
    status = "Enabled"
    expiration { days = var.retention_days }
  }
}

resource "aws_cloudwatch_log_group" "trail" {
  name              = "/aws/cloudtrail/org"
  retention_in_days = var.retention_days
}

Azure Log Analytics (CLI)

# Set workspace retention to 365 days
az monitor log-analytics workspace update \
  -g MyRG -n MyLAW --retention-time 365

NTP on Linux

timedatectl set-ntp true
timedatectl status | grep "System clock synchronized"

Evidence to capture: Terraform plan/apply output, Azure CLI command logs, timedatectl status, and screenshots of the console settings.


Step 4 — Lock down TLS & headers (network ODPs)

Nginx TLS and HSTS

ssl_protocols TLSv1.2 TLSv1.3;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;

Apache

SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "DENY"

Evidence: vhost files, a PR with diffs, and a post-deployment scan result attached to the ticket.


Step 5 — Enforce access reviews & deprovisioning

Disable inactive users (example: Linux + SSO directory export)

# Deactivate local accounts not seen in last 30 days
while IFS=: read -r user _ uid gid _ home shell; do
  [ "$uid" -ge 1000 ] || continue
  last_login=$(lastlog -u "$user" | awk 'NR==2{print $4,$5,$6}')
  if [[ "$(date -d "$last_login" +%s)" -lt "$(date -d '30 days ago' +%s)" ]]; then
    sudo usermod --lock "$user"
  fi
done </etc/passwd

Quarterly access review reminder (GitHub Actions)

name: Quarterly Access Review
on:
  schedule:
    - cron: "0 9 1 */3 *" # 9:00 on the 1st, every 3rd month
jobs:
  notify:
    runs-on: ubuntu-latest
    steps:
      - name: Post Slack reminder
        run: |
          curl -X POST -H 'Content-type: application/json' \
          --data '{"text":"ODP: Access review due this week. Export and attest."}' $SLACK_WEBHOOK

Step 6 — Turn every fix into C3PAO-ready evidence

Automated “evidence bundle” collector

#!/usr/bin/env bash
set -euo pipefail
STAMP=$(date +%Y%m%d-%H%M%S)
DEST="evidence/$STAMP"
mkdir -p "$DEST"

# Capture configs
cp /etc/ssh/sshd_config "$DEST/"
cp /etc/nginx/nginx.conf "$DEST/" 2>/dev/null || true
timedatectl status > "$DEST/timedatectl.txt"

# Save command proofs
echo "az monitor log-analytics workspace show ..." > "$DEST/commands.txt"

# Hash everything
( cd "$DEST" && sha256sum * > SHA256SUMS.txt )

zip -r "evidence-bundle-$STAMP.zip" "$DEST"
echo "Evidence bundle created: evidence-bundle-$STAMP.zip"

Redact PII in logs before sharing (Python)

import re, sys
pii = re.compile(r"(\b\d{3}-\d{2}-\d{4}\b|\b\d{16}\b|[\w\.-]+@[\w\.-]+)")
for line in sys.stdin:
    print(pii.sub("[REDACTED]", line), end="")

Attach the ZIP and sanitized logs to your ticket; link the PR and deployment job run. That’s the artifact chain assessors expect.


Step 7 — Validate, retest, and show “before/after”

Use a short CI/CD job to run a post-change web exposure check and store artifacts.

name: Post-Change Exposure Check
on: [workflow_dispatch]
jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - name: Run external sweep
        run: |
          # Document the check; store raw results + HTML report artifact
          curl -s https://free.pentesttesting.com/ > scan-landing.html
          echo "Manual step: run site scan in browser & upload report to artifacts/"
      - uses: actions/upload-artifact@v4
        with:
          name: exposure-check
          path: |
            scan-landing.html
            artifacts/**

Free Website Vulnerability Scanner — Landing page screenshot

Here, you can view the interface of our free tools webpage, which offers multiple security checks. Visit Pentest Testing’s Free Tools to perform quick security tests.
Here, you can view the interface of our free tools webpage, which offers multiple security checks. Visit Pentest Testing’s Free Tools to perform quick security tests.

30/60/90-day CMMC L2 remediation plan (owner + SLA)

WindowFocusExamplesEvidence you’ll keep
Day 0–30High-impact ODPsSession/JWT timeouts; TLS/HSTS; SSH/Windows idleConfigs, PRs, deploy logs, header scans
Day 31–60Logging & monitoring365-day retention; time sync; alerting rulesIaC plans, SIEM screenshots, alert tests
Day 61–90Access & resilienceQuarterly reviews; deprovisioning; backup testsReview sign-offs, disablement logs, restore proof

Map findings to 800-171r3 controls (working model)

# controls-map.yaml (excerpt)
AC-12:  # Session termination
  odp: session.idle_timeout_seconds
  evidence:
    - /etc/ssh/sshd_config
    - group-policy/registry-exports
    - web/jwt-config.md
AU-11:  # Retention
  odp: logging.retention_days
  evidence:
    - terraform/cloudtrail.tf
    - az/log-analytics-retention.txt
SC-13:  # Cryptographic protection
  odp: network.tls_min_version
  evidence:
    - nginx/nginx.conf
    - apache/ssl.conf
IA-2:   # MFA
  odp: auth.mfa_required
  evidence:
    - idp/policy-export.json

Add “proof of fix” checks your assessors will love

KQL (Azure/M365) — suspicious admin actions in the last 24h

AuditLogs
| where TimeGenerated > ago(24h)
| where ResultType == "Success"
| where OperationName has_any ("Add service principal", "Update app role assignment", "Reset user password")
| project TimeGenerated, OperationName, InitiatedBy, TargetResources, ResultDescription

SQL — Who changed access last quarter?

SELECT actor, action, target, ts
FROM access_change_audit
WHERE ts >= DATE_TRUNC('quarter', NOW()) - INTERVAL '1 quarter';

CI guardrail — block merges if ODPs drift

- name: Verify ODP drift
  run: |
    jq -r '.session.idle_timeout_seconds' odps.json | grep -qx '900'

Sample Report Screenshot to check Website Vulnerability — After a scan

A sample vulnerability report provides detailed insights into various vulnerability issues, which you can use to enhance your application’s security.
A sample vulnerability report provides detailed insights into various vulnerability issues, which you can use to enhance your application’s security.

Related services (fastest path to done)


Recently on our blog (keep learning)


Final Note

Need a CMMC Level 2 remediation partner who ships fixes and artifacts?
👉 Start with a quick consult via our Risk Assessment or Remediation pages, or email [email protected].


P.S. If you want a “done-for-you” plan, we’ll lift your ODPs into IaC, wire the pipelines, and hand you a clean CMMC Level 2 remediation evidence bundle—ready for review.

Free Consultation

If you have any questions or need expert assistance, feel free to schedule a Free consultation with one of our security engineers>>

🔐 Frequently Asked Questions (FAQs)

Find answers to commonly asked questions about CMMC Level 2 Remediation.

Leave a Comment

Scroll to Top
Pentest_Testing_Corp_Logo
Privacy Overview

This website uses cookies so that we can provide you with the best user experience possible. Cookie information is stored in your browser and performs functions such as recognising you when you return to our website and helping our team to understand which sections of the website you find most interesting and useful.