← Back to Blog

How to Use Nark as CC8.1 Evidence in Your SOC 2 Report

By Caleb Gates

To generate CC8.1 change-management evidence from Nark, run the scanner on every pull request in CI, pipe the resulting JSON audit records to your compliance evidence store (Vanta, Drata, Secureframe, or a plain S3 archive), and cite those records under the CC8.1 control narrative as the "testing" step in your authorize-design-develop-test-approve-implement chain. Each scan record is timestamped, immutable, and references the specific file, line, Nark Profile, and postcondition. That is the exact shape SOC 2 auditors accept as change-management testing evidence.

Quick answer: Install Nark in CI. Configure it to write a JSON report per scan. Route those reports to your evidence store. Cite them in your CC8.1 control narrative as one of the enumerated pre-merge tests. To wire it up in under 10 minutes, follow the CI setup guide.


What CC8.1 actually says

CC8.1 sits in the Common Criteria section of the AICPA Trust Services Criteria. The plain-English version: the entity authorizes, designs, develops, tests, approves, and implements changes to infrastructure, data, software, and procedures. Auditors read that as a six-step chain, and they want documented evidence at each step.

The step that most engineering teams underweight is "tests." Auditors are not satisfied by a general statement that "we test our code." They want to see that a repeatable, machine-checked test ran against the specific change, that it either passed or blocked the merge, and that the log survives long enough for the observation window to cover.

That is what a CI test suite already gives you. It is also what a CI-integrated static analyzer gives you. Nark falls squarely in the second category.

The evidence problem for CC8.1

Most companies do fine on the "authorize" and "approve" side of CC8.1. They have a ticketing system, a PR review requirement, and a manager sign-off flow. Those artifacts are easy to produce at audit time.

The scramble usually happens on the "test" side. When the auditor asks "prove that every code change in the observation period was tested before it merged," teams often end up reconstructing evidence from GitHub Actions logs that were never designed to be an audit trail. The logs are there. The mapping from "PR #4831 merged on May 3" to "these specific tests ran and passed" is technically inferable but ugly to produce under time pressure.

The right shape of evidence has three properties. It is per-change, meaning one artifact per PR. It is testable, meaning the record itself contains the specific outcome (pass, fail, list of findings). And it is immutable, meaning the artifact cannot be quietly rewritten after the fact. If your PR-time tests write records that meet those three properties and land in a compliance evidence store, CC8.1 becomes a filing exercise instead of a reconstruction exercise.

How Nark's scan output maps to those three properties

Every Nark scan writes a structured JSON record when it runs. The relevant properties for CC8.1 evidence:

Per-change. Nark runs on every pull request when configured through GitHub Actions, GitLab CI, or CircleCI. Each PR produces one scan artifact. The commit SHA, the branch, the PR number, the timestamp, and the Nark version are all captured in the record. If your control narrative says "every code change is scanned by Nark before merge," the per-PR artifact is the proof.

Testable. The record contains the scan's outcome. In enforcing mode, a violation blocks the merge. In advisory mode, the violation is reported without blocking. Either way the record shows what fired and where. Each finding cites the file path, the line number, the Nark Profile that matched, and the specific postcondition that was breached. An auditor reading the record can see exactly what was tested.

Immutable. Once written to your evidence store, the record is a compliance artifact under whatever retention policy your store enforces. It is not a live GitHub log that can be rotated out. Vanta, Drata, and Secureframe treat evidence store entries as write-once by default; a plain S3 archive with versioning enabled behaves the same way.

The three properties map cleanly onto how auditors read CC8.1. Per-change proves coverage across the observation window. Testable proves a real test ran, not just a checkbox click. Immutable proves the record is trustworthy at audit time.

Setting up Nark for CC8.1 evidence

The full CI setup lives at /docs/ci-setup. The short version, for GitHub Actions:

name: Nark scan
on: [pull_request]

jobs:
  nark:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm ci
      - run: npx nark --tsconfig ./tsconfig.json --output nark-report.json
      - uses: actions/upload-artifact@v4
        with:
          name: nark-report-${{ github.event.pull_request.number }}
          path: nark-report.json
          retention-days: 90

Three things to notice. The --output flag emits the structured JSON that becomes the audit record. The upload-artifact step attaches the record to the GitHub Actions run, giving you a stable URL and a documented retention window. The retention-days value should match or exceed your Type II observation period, or you should sync the artifact to a longer-lived store.

For teams already on Vanta or Drata, add a custom integration or custom connection that pulls the scan artifact into the evidence store on every merge. For teams without one of those platforms, a scheduled S3 sync of the artifacts directory (weekly is fine) covers the same ground.

Sample audit record and how to hand it to your auditor

A trimmed example of what one scan record looks like:

{
  "scan_id": "scan_2026-07-22T18-04-12Z_c9f4a1",
  "timestamp": "2026-07-22T18:04:12Z",
  "nark_version": "3.2.0",
  "commit_sha": "c9f4a1b2e8...",
  "pr_number": 4831,
  "tsconfig_path": "./tsconfig.json",
  "profiles_loaded": 169,
  "violations": [
    {
      "file": "apps/api/src/routes/checkout.ts",
      "line": 47,
      "profile": "stripe",
      "postcondition": "stripe-charges-create-must-catch-stripe-card-error",
      "severity": "error",
      "message": "stripe.charges.create call not wrapped in a catch that handles StripeCardError"
    }
  ],
  "violations_count": 1,
  "outcome": "blocked",
  "run_url": "https://github.com/acme/api/actions/runs/9128412734"
}

When you hand this to your auditor, the framing is: the control narrative already lists PR checks that are required to merge. Nark is one of those enumerated checks. This record is the artifact proving the check ran against this specific commit at this specific time and produced this specific outcome. The record shows a blocked merge, meaning the change was refused until the violation was fixed. If the outcome were clean with an empty violations array, that would prove the change was tested and passed.

Auditors do not need to understand what a Nark Profile is in detail. They need to see that a defined test ran, that it produced a pass or fail, and that the log is trustworthy. All three are visible in the record.

Related evidence sources for the other Common Criteria

Nark is one input in a larger evidence pile. For a full picture, the other Common Criteria most engineering leaders map at the same time:

  • CC7.1 (detection of newly introduced vulnerabilities). Nark contributes to this too. Package misuse is a class of vulnerability the CVE feed does not catch, and Nark's scheduled main-branch scans give you ongoing monitoring evidence. Pair with Snyk, Socket, or Dependabot for known-CVE coverage.
  • CC7.2 (analysis of anomalies). Sentry, Datadog, and New Relic. Runtime tools that catch what static scanners miss.
  • CC7.3 and CC7.4 (incident response and remediation). Your on-call system, PagerDuty runbooks, and postmortem archive.
  • CC7.5 (recovery). Backup restore drills. Not scanner-adjacent.
  • CC8.1 (change management). Nark's PR-time scans, alongside your test suite, CI-run history, and PR review records.

The SOC 2 page walks through the CC7.1 mapping in detail.

What Nark does not satisfy on its own

Being direct. Nark is not a complete CC8.1 story by itself, and no scanner is.

CC8.1 covers six steps: authorize, design, develop, test, approve, implement. Nark contributes to "test." The other five steps live in your ticketing system (authorize), your design docs (design), your source control (develop), your PR review requirement (approve), and your deploy pipeline (implement). All of those need their own evidence.

Nark is also not a general-purpose test suite. It scans for one specific class of bug: missing or incorrect handling of documented failure modes from packages you already trust. Your existing unit and integration tests remain the primary evidence that functional requirements are met. Nark sits alongside them.

And Nark alone does not cover CC7.1. Package misuse is a partial input. To close the CC7.1 loop you also need a known-CVE scanner (Snyk, Socket, Dependabot, or GitHub Advanced Security), and typically a custom-code taint analyzer (Semgrep, Snyk Code, or CodeQL) for the parts of the vulnerability surface that live in your own dataflow.

The honest framing when you talk to your auditor: Nark is one enumerated pre-merge test that adds a specific class of coverage the other tests miss. It is not the whole control.

Adding Nark mid-observation-window

A common question from teams already inside a Type II observation period: is it too late to add Nark?

No, but document it. Introduce Nark to CI, note the introduction in your standard change-management log, and start generating scan artifacts from that date forward. The auditor will see partial coverage of the window, which is fine as long as the addition itself is documented. The pattern that raises eyebrows is introducing a control the week before the auditor arrives without any change record. Adding a control mid-window and treating it like a normal change is the well-behaved shape.

Going forward, aim to have Nark scans generated for the full next observation window. That is the cleanest position when the next Type II cycle comes around.

Getting started

Wire Nark into CI in under 10 minutes with the CI setup guide. For the full CC7.1 and CC8.1 mapping, read the SOC 2 page. For subprocessor and security-posture questions, see the trust page. To run Nark once against your own repo:

npx nark --tsconfig ./tsconfig.json

Compliance-specific questions go to compliance@nark.sh.