Skip to content
Stribog

Compliance

All writing

NIST 800-53 Rev 5 vs Rev 4: SR Family, Baselines, Privacy

NIST 800-53 Rev 5 restructured the catalogue: baselines left for SP 800-53B, privacy folded in, and a new SR family whose provenance control no baseline picks.

Stribog13 min read

Most explanations give the same four bullets: two new families, more controls, privacy integrated, baselines moved. All true, all insufficient. They tell you the catalogue changed shape — not which document answers which question, where a withdrawn control's content went, or which supply chain controls a baseline obliges you to select. Every figure below is reproducible from NIST's published files at a pinned tag.

Rev 4 was withdrawn in 2021; its vocabulary was not

CSRC's Rev 4 page records the consequence plainly: "This publication was officially withdrawn on September 23, 2021, one year after the publication of Revision 5 (September 23, 2020)." A questionnaire item still worded from Rev 4 quotes a withdrawn publication — easy to miss in a document written once and copied forward.

That matters practically. If an item asks how you satisfy SA-12, there is no SA-12: it is withdrawn and its content redistributed. Answering means knowing where each piece went — a different exercise from answering a control that still exists.

Nor is the current artefact the December 2020 PDF. On 27 August 2025 NIST issued Release 5.2.0, adding SA-15(13), SA-24 and SI-02(07). A separate article on mapping SP 800-53 to self-hosted Kubernetes walks that release's totals; this one stays on the Rev 4-to-Rev 5 delta and SR.

The five structural changes, in NIST's own words

Rev 5's executive summary lists seven most significant changes. These five move where an answer lives; read them verbatim rather than in paraphrase:

  • "Making the controls more outcome-based by removing the entity responsible for satisfying the control (i.e., information system, organization) from the control statement" — the control no longer says who acts; your implementation description must.
  • "Integrating information security and privacy controls into a seamless, consolidated control catalog" — privacy is no longer a separate appendix to cross-reference.
  • "Establishing a new supply chain risk management control family" — SR, the subject of the rest of this article.
  • "Removing control baselines and tailoring guidance from the publication and transferring the content to NIST SP 800-53B, Control Baselines for Information Systems and Organizations" — the catalogue no longer tells you what to select.
  • "Separating control selection processes from the controls, thereby allowing the controls to be used by different communities of interest" — engineers and architects, not only baseline selectors.

Applicability moved with it. Rev 4's §1.1 scoped the document to "organizations and information systems supporting the executive agencies of the federal government". Rev 5's opens: "The controls can be implemented within any organization or system that processes, stores, or transmits information", with mandatory use scoped separately to federal systems under OMB Circular A-130 and FISMA. That edit is why Rev 5 turns up in commercial procurement with no federal contract near it.

Structurally, Rev 4 organised controls "into eighteen families"; Rev 5 organises them "into 20 families". Seventeen align with FIPS 200. The three that do not — Program Management, PII Processing and Transparency, Supply Chain Risk Management — "address enterprise-level program management, privacy, and supply chain risk considerations pertaining to federal mandates emergent since [FIPS 200]". In NIST's framing SR answers a mandate that postdates the baseline requirements.

Rev 5 answers what a control requires; SP 800-53B answers whether you must select it. A Rev 4-worded questionnaire item is asking about a catalogue withdrawn in 2021.

Reproducing the delta instead of quoting it

NIST publishes a Rev 4-to-Rev 5 comparison workbook as supplemental material on the Rev 5 publication page, credited to MITRE for the Director of National Intelligence. Its Legend sheet defines the notations: "New base control" is "A base control that did not exist in Rev 4"; "Withdrawn" means "Withdrawn in Rev5", counting Rev 4's own withdrawals as unchanged.

Counting them is a short job with the standard library, because an .xlsx is a ZIP archive of XML. No spreadsheet application, no openpyxl, no reason to trust a figure quoted in an article — this one included.

python
#!/usr/bin/env python3
"""Count Rev 4-to-Rev 5 changes in NIST's comparison workbook, stdlib only.

An .xlsx is a ZIP of XML, so nothing needs installing. Counts the notations
the workbook's own Legend sheet defines. Tested on Python 3.11.
usage: rev4-rev5-delta.py sp800-53r4-to-r5-comparison-workbook.xlsx
"""
import collections, re, sys, zipfile
# Stdlib ElementTree by design — nothing to install. One checksummed file from
# csrc.nist.gov; for untrusted spreadsheets use defusedxml instead.
import xml.etree.ElementTree as ET

M = "{http://schemas.openxmlformats.org/spreadsheetml/2006/main}"
R = "{http://schemas.openxmlformats.org/officeDocument/2006/relationships}"
SHEET = "Rev4 Rev5 Compared"
NOTATIONS = ("New base control", "New control enhancement", "Withdrawn")

with zipfile.ZipFile(sys.argv[1]) as z:
    strings = [
        "".join(t.text or "" for t in si.iter(f"{M}t"))
        for si in ET.fromstring(z.read("xl/sharedStrings.xml"))
    ]
    book = ET.fromstring(z.read("xl/workbook.xml"))
    rels = {
        r.get("Id"): r.get("Target")
        for r in ET.fromstring(z.read("xl/_rels/workbook.xml.rels"))
    }
    rid = next(s.get(f"{R}id") for s in book.iter(f"{M}sheet") if s.get("name") == SHEET)
    sheet = ET.fromstring(z.read("xl/" + rels[rid].lstrip("/").removeprefix("xl/")))


def cell_text(cell):
    v = cell.find(f"{M}v")
    if cell.get("t") == "s" and v is not None:
        return strings[int(v.text)]
    if cell.get("t") == "inlineStr":
        return "".join(t.text or "" for t in cell.iter(f"{M}t"))
    return v.text if v is not None else ""


counts, sr_counts, rows = collections.Counter(), collections.Counter(), 0
for row in sheet.iter(f"{M}row"):
    rows += 1
    cells = [cell_text(c) or "" for c in row]
    blob = " ".join(cells)
    for notation in NOTATIONS:  # one notation per row, first match wins
        if notation in blob:
            counts[notation] += 1
            if cells and re.match(r"^SR-\d", cells[0].strip()):
                sr_counts[notation] += 1
            break

print(f"rows on '{SHEET}': {rows}")
for notation in NOTATIONS:
    print(f"{notation:<26} {counts[notation]}")
print(f"SR-family rows marked new: {sum(sr_counts.values())} -> {dict(sr_counts)}")
rev4-rev5-delta.py: count the workbook's own change notations without installing anything. One notation per row, first match wins, so a row is never double-counted.

Run on 16 September 2026 against the workbook CSRC currently serves, that prints 1,191 rows: 66 new base controls, 202 new enhancements, 90 withdrawn. Stribog's own counts from that file, not NIST headline figures, and they carry its vintage: the comparison predates Release 5.2.0 and omits the three controls it added. Use it for the delta, not the current catalogue.

SR is a new family, and SA-12's pieces did not all land in it

The same script reports the second figure: all 27 SR rows — twelve base controls, fifteen enhancements — carry a new-control notation. SR-1's notation cell reads "New base control", the next "Adds to L, M, and H Security Control Baselines (SP 800-53B)". In NIST's own accounting the family is new, not a rename.

Vendor explainers routinely collapse this with a separate fact. Rev 4's SA-12, Supply Chain Protection, is withdrawn, and SP 800-53B's SA-family withdrawn table records a destination for the base control and all fifteen enhancements. Thirteen land in SR: (1) to SR-5, (2) to SR-6, (3) and (15) into SR-3, (4) to SR-3(1), (5) to SR-3(2), (6) into SR-5(1), (7) to SR-5(2), (9) to SR-7, (10) to SR-4(3), (11) to SR-6(1), (12) to SR-8, and (14) to SR-4(1) and SR-4(2).

The control worth reading in full is SR-4, Provenance. One sentence: "Document, monitor, and maintain valid provenance of the following systems, system components, and associated data: [Assignment: organization-defined systems, system components, and associated data]." Rev 5 defines the term — "Provenance is the chronology of the origin, development, ownership, location, and changes to a system or system component and associated data." SR-4(3), where SA-12(10) landed, requires controls "to validate that the system or system component received is genuine and has not been altered".

Read those beside a pipeline that signs commits, resolves tags to digests and attaches a signed SBOM attestation, and the overlap is not approximate. Origin, ownership, location and changes are what that pipeline records; genuine-and-not-altered is what signature verification asserts. Which sharpens the baseline question rather than settling it.

Which SR controls a baseline actually selects

SP 800-53B gives the shape of the answer first: the SR controls "are allocated to the low-impact, moderate-impact, and high-impact security control baselines and the privacy control baseline, as appropriate". Allocation is per-control. A new family does not arrive wholesale in your selection.

Table 3-20 carries the marks, but the machine-readable form is better evidence: you can diff it. NIST publishes resolved baseline profiles — catalogues already reduced to the controls a baseline selects — in usnistgov/oscal-content. Fetch them at a pinned tag, never at main:

bash
#!/usr/bin/env bash
# fetch-oscal-baselines.sh: pin, fetch and checksum NIST's OSCAL Rev 5 files.
# usage: fetch-oscal-baselines.sh [tag] [output-dir]
set -euo pipefail

TAG="${1:-v1.4.0}"
OUT="${2:-oscal-${TAG}}"
BASE="https://raw.githubusercontent.com/usnistgov/oscal-content/${TAG}/nist.gov/SP800-53/rev5/json"

for bin in curl jq sha256sum; do
  command -v "$bin" >/dev/null || { echo "missing: $bin" >&2; exit 127; }
done
files=(
  NIST_SP-800-53_rev5_catalog.json
  NIST_SP-800-53_rev5_LOW-baseline-resolved-profile_catalog.json
  NIST_SP-800-53_rev5_MODERATE-baseline-resolved-profile_catalog.json
  NIST_SP-800-53_rev5_HIGH-baseline-resolved-profile_catalog.json
)

mkdir -p "$OUT"
for f in "${files[@]}"; do
  curl -fsSL -o "${OUT}/${f}" "${BASE}/${f}"
done
( cd "$OUT" && sha256sum "${files[@]}" | tee SHA256SUMS )

# Read metadata.version, not the title: at v1.4.0 the HIGH profile still
# titles itself "Revision 5.1.1 HIGH IMPACT BASELINE" at version 5.2.0.
for f in "${files[@]}"; do
  jq -r --arg f "$f" \
    '.catalog.metadata | "\($f)  version=\(.version)  oscal=\(."oscal-version")"' \
    "${OUT}/${f}"
done
fetch-oscal-baselines.sh: pull the catalogue and the three resolved impact-baseline profiles at a pinned tag, checksum them, and print metadata.version rather than the title.

That mismatch is not cosmetic. At tag v1.4.0 the HIGH resolved profile is titled "Revision 5.1.1 HIGH IMPACT BASELINE" while its metadata.version reads 5.2.0. Anyone reading the title hunts for a newer file that does not exist. Check the version field.

With the profiles on disk, membership is a set walk — recursive, because enhancements nest inside their base controls:

python
#!/usr/bin/env python3
"""Print SR-family baseline membership from NIST's OSCAL resolved profiles.

Run where fetch-oscal-baselines.sh wrote. Stdlib only; tested on Python 3.11.
"""
import json, pathlib, re

CATALOG = "NIST_SP-800-53_rev5_catalog.json"
BASELINES = {
    "L": "NIST_SP-800-53_rev5_LOW-baseline-resolved-profile_catalog.json",
    "M": "NIST_SP-800-53_rev5_MODERATE-baseline-resolved-profile_catalog.json",
    "H": "NIST_SP-800-53_rev5_HIGH-baseline-resolved-profile_catalog.json",
}


def walk(node, out):
    """Collect every control id, including nested enhancements."""
    for control in node.get("controls", []):
        out.add(control["id"])
        walk(control, out)
    for group in node.get("groups", []):
        walk(group, out)



selected = {}
for mark, filename in BASELINES.items():
    ids = set()
    walk(json.loads(pathlib.Path(filename).read_text())["catalog"], ids)
    selected[mark] = ids
    print(f"# {mark}: {len(ids)} control ids")

# Rows come from the catalogue: a control no baseline selects must still be
# a row, or its empty row cannot print.
catalog = json.loads(pathlib.Path(CATALOG).read_text())["catalog"]
sr_all = set()
walk(next(g for g in catalog["groups"] if g["id"] == "sr"), sr_all)

sr_ids = sorted(
    sr_all, key=lambda c: ([int(n) for n in re.findall(r"\d+", c)] + [0])[:2]
)

print(f"\n{'control':<10} {'L':^3} {'M':^3} {'H':^3}")
for control_id in sr_ids:
    marks = " ".join(
        " x " if control_id in selected[m] else " . " for m in ("L", "M", "H")
    )
    print(f"{control_id:<10} {marks}")
sr-baselines.py: print SR-family membership across LOW, MODERATE and HIGH from the resolved profiles. The row with no marks is the point of the table.

At tag v1.4.0 on 16 September 2026 that prints 149 ids in LOW, 287 in MODERATE, 370 in HIGH, and all 27 SR rows, of which fourteen carry a mark. Ten of the twelve base controls appear — SR-1, SR-2, SR-3, SR-5, SR-8, SR-10, SR-11, SR-12 in all three; SR-6 in MODERATE and HIGH; SR-9 in HIGH only — plus four of the fifteen enhancements: SR-2(1), SR-11(1) and SR-11(2) in all three; SR-9(1) in HIGH only.

The rows that never print a mark are the interesting ones. SR-4 and all four of its enhancements — SR-4(1), SR-4(2), SR-4(3), SR-4(4) — are selected by none of LOW, MODERATE or HIGH. Neither is SR-7. The control that reads like a signed build pipeline is the one no impact baseline obliges you to implement; what every baseline does select runs to policy, plans, contracts, notification agreements and disposal records.

Ten of twelve SR base controls are selected by at least one baseline, and almost all of them are procurement and process. Neither SR-4 nor SR-7 is selected by any — and SR-4 is the one a build pipeline evidences directly.

What your existing provenance evidence does and does not cover

SP 800-53A Rev 5 splits SR-4 into three determinations — that valid provenance "is documented", "is monitored" and "is maintained". Its Examine list names what an assessor looks at, including "documentation showing the history of ownership, custody, and location of and changes to critical systems or critical system components" — a description of a git history, a digest chain and a signature log, written before that tooling was standard.

SP 800-161r1's C-SCRM guidance for SR-4 tells enterprises to "consider producing SBOMs for applicable and appropriate classes of software", that "SBOMs should be digitally signed using a verifiable and trusted key", and that they "can play a critical role in enabling organizations to maintain provenance". If you already generate signed SBOMs — the mechanics are in Syft, Grype and the blind spots between them and SBOM, Sigstore and admission control — the evidence exists before the control is selected.

The same document names the failure mode, worth quoting at anyone treating an SBOM as a finished answer: "SBOMs and the improved transparency that they are meant to provide for organizations are a complementary, not substitutive, capability." SR-4 wants provenance documented, monitored and maintained. Generating an SBOM documents; it monitors nothing.

So the bundle is not one file: the commit range behind a release tag, the digest it resolved to, and an attestation that was verified rather than merely fetched — dated, and re-assembled on a schedule so "maintained" has evidence behind it. Mapping those artefacts onto SR controls is an engineering position, not a NIST crosswalk.

bash
#!/usr/bin/env bash
# sr4-evidence.sh: assemble one image's SR-4 provenance bundle.
set -euo pipefail

REGISTRY="${REGISTRY:?set REGISTRY, e.g. registry.example.com/platform}"
IMAGE="${IMAGE:?set IMAGE, e.g. api-gateway}"
TAG="${TAG:?set TAG, e.g. v1.8.3}"
IDENTITY="${IDENTITY:?set IDENTITY, the certificate identity regexp}"
ISSUER="${ISSUER:-https://token.actions.githubusercontent.com}"

OUT="evidence/$(date -u +%Y-%m-%d)/${IMAGE}-${TAG}"
mkdir -p "$OUT"

# Origin, development, changes: commits this release added, and who signed the tag.
# No previous tag (first release) leaves the range open-ended at $TAG.
PREV="$(git describe --tags --abbrev=0 "${TAG}^" 2>/dev/null || true)"
git log --pretty=format:'%H %aI %an %s' "${PREV:+${PREV}..}${TAG}" > "${OUT}/commits.txt"
# Record the verdict either way: an unsigned tag is a finding, not a fatal error.
git tag --verify "$TAG" > "${OUT}/tag-signature.txt" 2>&1 \
  || echo "UNVERIFIED: no valid GPG signature on $TAG" >> "${OUT}/tag-signature.txt"

# Location and custody: the immutable digest the tag resolved to.
crane digest "${REGISTRY}/${IMAGE}:${TAG}" > "${OUT}/digest.txt"
DIGEST="$(cat "${OUT}/digest.txt")"

# Ownership and authenticity: verified, not merely downloaded.
cosign verify-attestation \
  --type spdxjson \
  --certificate-identity-regexp "$IDENTITY" \
  --certificate-oidc-issuer "$ISSUER" \
  "${REGISTRY}/${IMAGE}@${DIGEST}" > "${OUT}/sbom-attestation.json"

printf 'SR-4 bundle written to %s\n' "$OUT"
sr4-evidence.sh: one dated provenance bundle per image. Registry, image, tag and the Sigstore issuer are site-specific, so they are parameters rather than literals.

Baselines left the document: tailoring is a separate step now

SP 800-53B holds "three security control baselines (one for each system impact level—low-impact, moderate-impact, and high-impact), as well as a privacy baseline that is applied to systems irrespective of impact level", plus tailoring guidance and "guidance on the development of overlays to facilitate control baseline customization for specific communities of interest, technologies, and environments of operation".

Adding SR-4 to your selection becomes an explicit, recorded act rather than a side effect of inheriting a baseline. Overlays are the mechanism: a documented customisation of a baseline for a specific technology or environment. A team that builds its own images is that community of interest.

The same reasoning runs the other way when you assess a vendor rather than being assessed — concentration risk and third-party exit evidence — and it is the loop NIST CSF 2.0's GOVERN function formalises. A control selected on purpose has a rationale; an inherited one has a checkbox.

One piece of history worth dating correctly, because it is still quoted as current: FedRAMP's Rev 5 transition guide, version 1.0 dated 30 May 2023, records that the PMO "updated the FedRAMP baseline security controls, documentation, and templates to reflect the changes in NIST SP 800-53, Rev. 5." That is a dated statement about the PMO's own baselines and templates, in a document that is itself a transition plan.

Exit ramp: keep the mapping in the format the catalogue already uses

A control-to-evidence mapping inside a GRC vendor's database is a hostage. Held as an OSCAL component definition in your own repository it is a file you can diff, review and take with you — in NIST's own publication format. A separate article argues that at length; below is the SR delta.

json
{
  "component-definition": {
    "uuid": "8f2c1e14-6b4a-4c52-9a3d-1f0b7e5c2a90",
    "metadata": {
      "title": "Self-built container platform: SR control implementations",
      "last-modified": "2026-09-16T00:00:00Z",
      "version": "1.0.0",
      "oscal-version": "1.1.3"
    },
    "components": [
      {
        "uuid": "1c9a0b77-3d51-42ef-8a2b-6e4c05d1937f",
        "type": "service",
        "title": "Image build and admission pipeline",
        "description": "Signed commits, digest-pinned images, signed SBOM attestations, admission verification.",
        "control-implementations": [
          {
            "uuid": "b34d6f02-5e18-4a7c-9d60-2f81ca4e7b55",
            "source": "https://raw.githubusercontent.com/usnistgov/oscal-content/v1.4.0/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_catalog.json",
            "description": "SR controls selected by overlay, not inherited from an impact baseline.",
            "implemented-requirements": [
              {
                "uuid": "0a7e5d19-9c3b-4f86-b1d2-77e0a6c4318e",
                "control-id": "sr-4",
                "description": "Dated bundle per release: commit range, verified tag signature, resolved registry digest. Monitored by the weekly re-assembly job, maintained by retaining every prior bundle."
              },
              {
                "uuid": "5d2f8c60-41ab-4e93-ae17-c3b9026d4f8a",
                "control-id": "sr-4.3",
                "description": "cosign verify-attestation against a pinned certificate identity and OIDC issuer, in CI and again at admission."
              },
              {
                "uuid": "e61b3a94-7f02-4d58-93c5-8a4207be15d3",
                "control-id": "sr-11",
                "description": "Admission policy refuses images without a verifiable signature, preventing unauthentic components entering the system."
              }
            ]
          }
        ]
      }
    ]
  }
}
component-definition.json: the SR controls above, mapped to the artefact that evidences each. Control ids are lowercase and dotted in OSCAL — sr-4, sr-4.3, sr-11.

The long game: a revision migration should be a diff

The Rev 4-to-Rev 5 migration cost a re-read of a 492-page document and a manual crosswalk of every withdrawn control — which is how SA-12(8), which leaves the supply chain family altogether, ends up filed under SR by assumption. That is not inattention. It is what working from prose produces.

Rev 6 will come — as will the next version of every framework above it, and of the base images underneath, which is why building your own is the same argument a layer down. A mapping held in a spreadsheet makes a revision another re-read. An OSCAL component definition pinned to a catalogue tag makes it a diff: fetch the tag, compare ids, review what moved.

Pin the tag you ingest, checksum it, re-run the SR membership script when you bump it. Baseline allocation is data, and data that changed under you is detectable. That is the difference between owning a compliance position and renting one.

§FAQ/Common questions

Frequently asked

What changed in NIST 800-53 Rev 5 compared to Rev 4?

Four structural changes and one addition. Control statements became outcome-based by removing the entity responsible for satisfying them; privacy controls were integrated into one consolidated catalogue instead of Rev 4's Appendix J with its own eight families; the control baselines and tailoring guidance were removed from the publication and transferred to SP 800-53B; and control selection was separated from the controls. The addition is a new supply chain risk management family, SR. Rev 4's eighteen families became Rev 5's twenty.

Is NIST SP 800-53 Rev 4 still valid?

No. CSRC records that Rev 4 was officially withdrawn on 23 September 2021, one year after Rev 5 was published on 23 September 2020. Questionnaires and templates still worded from Rev 4 are quoting a retired publication, and a Rev 4 identifier such as SA-12 has no Rev 5 equivalent to answer directly — its content was redistributed across SR, RA and MA controls.

Which NIST 800-53 SR controls are in the moderate baseline?

Walking NIST's OSCAL resolved MODERATE profile at tag v1.4.0 on 16 September 2026 gives SR-1, SR-2, SR-2(1), SR-3, SR-5, SR-6, SR-8, SR-10, SR-11, SR-11(1), SR-11(2) and SR-12. SR-4 Provenance and its four enhancements are absent, as is SR-7; SR-9 and SR-9(1) appear only in HIGH. That is a reproduction from the published files with the script in this article, not a NIST-published table.

Where did SA-12 go in Rev 5?

SP 800-53B's withdrawn-controls table for the SA family records a destination for the base control and all fifteen enhancements. SA-12 itself moved to the SR family. Thirteen of the fifteen enhancements map into SR — SR-3, SR-3(1), SR-3(2), SR-4(1), SR-4(2), SR-4(3), SR-5, SR-5(1), SR-5(2), SR-6, SR-6(1), SR-7 and SR-8. The other two leave the family, landing on three controls outside it: SA-12(8) into RA-3(2), and SA-12(13) into MA-6 and RA-9.

Does a signed SBOM satisfy SR-4 Provenance?

Not on its own. SR-4 requires provenance to be documented, monitored and maintained, and SP 800-53A Rev 5 assesses those as three separate determinations. SP 800-161r1 encourages signed SBOMs and says they can play a critical role in maintaining provenance, but states directly that they are a complementary, not substitutive, capability. An SBOM documents; a scheduled re-assembly and retention of dated bundles is what evidences monitoring and maintenance.

nist 800 53 rev 5nist 800-53 rev 5 vs rev 4nist 800-53 sr familynist 800-53b control baselinessp 800-53 rev 4 withdrawnsr-4 provenance control

Executive Briefing

Thirty minutes to clarify your infrastructure risk

Walk us through your vendor footprint and regulatory constraints. We will tell you honestly where sovereignty creates leverage — and where it does not. No pitch deck. No obligation.