Skip to main content
INS // Insights

SOC 2 Evidence Freshness Tracking With TTL Flags

Updated September 2026 · 5 min read

A Type 2 sample is supposed to show the control operated during the observation window. What assessors still get is a folder of screenshots taken in month one, copied forward, and re-uploaded when the PBC list arrives. SOC 2 evidence freshness tracking is the small system we put in front of that folder: every artifact has a TTL, a collected_at, and a stale flag. If the sample is due on Friday, you do not discover on Thursday that the access-review export is ten months old.

This is not a new GRC product. It is a freshness layer on the store you already have — Drive, the GRC evidence locker, or the mapped store from SOC 2 ISO 27001 control mapping. AICPA SOC 2 Type 2 is about operating effectiveness over time. A single early screenshot is Type 1-shaped evidence wearing a Type 2 filename. See SOC 2 Type 1 vs Type 2 evidence.

Why SOC 2 Evidence Freshness Tracking Exists

Access reviews expire. Config drifts. A CloudTrail screenshot from the first month does not prove logging still worked in month nine. A terminated-user export from onboarding week does not prove CC6.3 removal still ran in the last quarter of the window.

Human coordinators remember some of this. They do not remember 80 artifacts across 20 systems. TTL is the reminder that does not take vacation.

The TTL Model We Attach

Each evidence type gets a default TTL. Each artifact instance gets collected_at and stale_at = collected_at + ttl.

Evidence type Typical TTL Why
Quarterly access review packet 1 quarter + grace CC6.2 is periodic
Termination sample (rolling) 30 days Must reflect recent leavers
IdP / AWS config screenshot 30 days Config drifts
CI OIDC trust policy 60 days Changes with repos
Policy PDF 1 year or next approval Slow-moving; still has an expiry
Continuous log proof 7–14 days Point-in-time is weak; refresh often

"Ten months" is the failure the search query is about: a screenshot that survived almost the entire Type 2 window without a refresh. We treat that as stale even if someone renamed the file final-final.

def freshness(artifact, as_of):
    stale_at = artifact.collected_at + timedelta(days=artifact.ttl_days)
    return {
        "id": artifact.id,
        "control": artifact.control_ids,
        "collected_at": artifact.collected_at,
        "stale_at": stale_at,
        "is_stale": as_of >= stale_at,
        "days_left": (stale_at - as_of).days,
    }

A nightly job writes is_stale and opens a ticket (or a GRC task) when days_left drops under a threshold. The PBC export excludes stale artifacts by default. You can still attach one with an override reason. That override is visible. Silent reuse is the bug.

Sampling Across the Window, Not Once

Type 2 testers pick dates inside the window. Freshness tracking therefore stores more than the latest file. We keep dated generations: Q1 review, Q2 review, Q3 review. The stale flag applies per generation. "We have an access review" is not the same as "we have an access review in the sampled quarter."

For continuous controls (logging, backups), we prefer a job that emits a small proof on a schedule — "restore test passed," "log destination still accepting" — over a heroic screenshot. AWS-ready architecture already has the telemetry. Freshness is making sure the proof is in the locker and not only in CloudWatch.

What We Flag Besides Age

  • Hash collision with a new filename — same bytes, new name, "updated" metadata. We hash on ingest.
  • Wrong window — artifact collected outside the observation period tagged on the campaign.
  • Wrong system — a staging screenshot filed under a production control. Owner + source_system on the record.
  • Missing successor — TTL elapsed and no newer artifact for that control. That is a coverage hole, not just a stale row.

SOC 2 access review packets are the highest-volume stale source we see. Config screenshots are second. Policy PDFs are rarely the problem; they are the excuse for not refreshing the first two.

How This Sits Next to Gap Analysis

Gap analysis automation finds systems with no artifact. Freshness finds systems with an old artifact. Both write into the same backlog. Mixing them into one "red/yellow/green" without saying which is which makes engineers refresh a screenshot when they should have built logging.

We do not claim the control is effective because the file is fresh. Fresh means eligible for the sample. Effective is the assessor's call.

Delivery Shape

For a mid-market locker:

  1. Inventory existing evidence objects (or start from the mapped store)
  2. Tag type → TTL
  3. Backfill collected_at from file timestamps where honest, else mark unknown (unknown is stale)
  4. Turn on the nightly flag + PBC filter
  5. Wire refresh jobs for the types we already automate (access exports, CloudTrail proofs)

The ceiling is a scheduled scanner over a catalog, not a new platform. If the catalog is 10,000 objects of scanned PDFs with no type, the first week is classification. We will say that up front.

SOC 2 evidence freshness tracking is security automation on the compliance locker. Internal-tool artifacts still need evidence for internal tools before they can have a TTL.

Ask us what your GRC platform is not covering: rutagon.com/contact · 907-841-8407 · contact@rutagon.com.

Frequently Asked Questions

What TTL should a Type 2 config screenshot have?

Thirty days is the default we use unless the control is truly static and the assessor has agreed a longer cycle. A screenshot from the first month of a long window is the failure this article is about.

Can we keep a stale artifact "for history"?

Yes. It stays in the store with is_stale=true. It does not appear in the default PBC packet. History is not a sample.

Does freshness tracking prove operating effectiveness?

No. It proves you did not submit an out-of-date file. The assessor still tests whether the control operated.

How do you detect a renamed duplicate screenshot?

Content hash on ingest. Same bytes and a new name still counts as the old collection time.

What if we do not know when a Drive file was actually captured?

We mark collected_at unknown and treat the artifact as stale until someone recaptures it. Guessing a date from memory is how ten-month screenshots survive.