Demo. Lumen Freight Co., its people and its vendors are fictional. Nothing connects to a real system.

Home

Control Monitoring.

A SOC 2 report tells you what a vendor says. These checks look at whether it is true inside the company, every day, and act when something drifts.

Sample last run Oct 20, 2026
  1. Step 1

    Pull

    Every morning, read the vendor inventory, identity provider, HR system, vendor app user lists and Google Workspace grants.

  2. Step 2

    Check

    Run each control as code. A failure becomes a finding with the evidence attached, so nobody has to screenshot anything for the auditor.

  3. Step 3

    Act

    Open a ticket for the owner, or undo the change on its own when that is safe. The finding closes when the next run passes.

Replay 30 days

30 daily runs of four checks on a sample company with 13 vendor apps in scope for SSO. 10 findings came up; 3 were still open on the last day. Press play, or drag to any day.

Oct 20 day 30 of 30

What changed this day

Nothing new. The checks ran and compared against yesterday.

Each strip is 30 days, one bar per daily run. Tap a control to filter the findings.

Open findings 3

HighDriftwood Analytics is not connected to the identity providerF-010 · SSO enforced · opened Oct 17, 3 days open

Ticket to the owner. Create the SSO app for Driftwood Analytics, move users over, then turn off password login.

Evidence

{
  "vendor": "Driftwood Analytics",
  "tier": 2,
  "data": "Internal",
  "idp_app": null
}
HighMeetMinutes can read all mail and is not a reviewed vendorF-009 · Shadow vendors · opened Oct 16, 4 days open

Ticket to the owner. Start vendor intake for MeetMinutes. If it is rejected, revoke the grant for all users.

Evidence

{
  "app": "MeetMinutes",
  "client_id": "meetminutes",
  "scopes": [
    "gmail.readonly"
  ],
  "granted_by": [
    "[email protected]"
  ],
  "first_grant": "2026-10-16"
}
MediumJules Park is an admin in Ledgerly without approvalF-008 · User access drift · opened Oct 13, 7 days open

Ticket to the owner. Approve it with a reason, or drop the account back to a standard user.

Evidence

{
  "app": "Ledgerly",
  "account": "[email protected]",
  "role": "admin",
  "approved_admins": [
    "[email protected]"
  ]
}

Closed 7

ClosedQuillpost contract ended 2026-10-08 but is still connectedF-007 · Vendor offboarding · opened Oct 9, closed Oct 15 (6 days)

Ticket to the owner. Revoke the keys first, then deactivate the SSO app and remove accounts. Ask the vendor for data deletion confirmation.

Evidence

{
  "vendor": "Quillpost",
  "contract_end": "2026-10-08",
  "still_open": [
    "API key ql-7f3a active",
    "OAuth grant in Google Workspace"
  ]
}
ClosedSlideGenie AI can read all Drive files and is not a reviewed vendorF-005 · Shadow vendors · opened Sep 30, closed Oct 7 (7 days)

Ticket to the owner. Start vendor intake for SlideGenie AI. If it is rejected, revoke the grant for all users.

Evidence

{
  "app": "SlideGenie AI",
  "client_id": "slidegenie",
  "scopes": [
    "drive.readonly"
  ],
  "granted_by": [
    "[email protected]",
    "[email protected]",
    "[email protected]"
  ],
  "first_grant": "2026-09-30"
}
ClosedSignalbox allows sign in without SSOF-001 · SSO enforced · opened Sep 21, closed Oct 6 (15 days)

Ticket to the owner. Turn on SSO enforcement for Signalbox and remove local accounts.

Evidence

{
  "vendor": "Signalbox",
  "idp_app": "signalbox",
  "sso_enforced": false,
  "password_login": true
}
ClosedMarcus Lee left on 2026-09-26 but still has SignalboxF-004 · User access drift · opened Sep 27, closed Oct 6 (9 days)

Ticket to the owner. Remove the Signalbox account and check its last sign in.

Evidence

{
  "app": "Signalbox",
  "account": "[email protected]",
  "role": "user",
  "hr_status": "terminated",
  "end_date": "2026-09-26"
}
ClosedPassword login was switched back on for Tidewater CRMF-006 · SSO enforced · opened Oct 3, closed Oct 4 (1 day)

Fixed automatically. Reverted automatically. Ask the admin who changed it whether a break glass account is needed.

Evidence

{
  "vendor": "Tidewater CRM",
  "idp_app": "tidewater",
  "sso_enforced": true,
  "password_login": true
}
ClosedContractor Dana Ortiz ended 2026-09-23, Mapline access still activeF-002 · User access drift · opened Sep 24, closed Sep 29 (5 days)

Ticket to the owner. Remove access, or get the contract extension and update the end date in HR.

Evidence

{
  "app": "Mapline",
  "account": "[email protected]",
  "role": "user",
  "type": "contractor",
  "end_date": "2026-09-23"
}
ClosedContractor Dana Ortiz ended 2026-09-23, Tidewater CRM access still activeF-003 · User access drift · opened Sep 24, closed Sep 29 (5 days)

Ticket to the owner. Remove access, or get the contract extension and update the end date in HR.

Evidence

{
  "app": "Tidewater CRM",
  "account": "[email protected]",
  "role": "user",
  "type": "contractor",
  "end_date": "2026-09-23"
}

The controls

Python, standard library only. The code below is exactly what produced the replay.

CCM-01 · Daily

SSO enforced

Is every in-scope vendor app behind SSO, with password login off?

A local login skips MFA and is missed when someone leaves. Vendors say they support SSO in their SOC 2; this checks that we actually turned it on.

Reads
Vendor inventory, Identity provider apps
When it fails
Password login switched back on for an SSO app is reverted automatically. Anything else opens a ticket for the app owner.
Maps to
SOC 2 CC6.1ISO 27001 A.8.5NIST CSF PR.AA-03
See the check sso.py
"""CCM-01 SSO enforced on vendor apps.

Every active vendor in tier 1 or 2 must sit behind the identity provider with
SSO enforced and local password login turned off. Local logins skip MFA and
survive offboarding, so this is the control that keeps the others honest.
"""

from datetime import date

CONTROL = {
    "id": "CCM-01",
    "name": "SSO enforced",
    "question": "Is every in-scope vendor app behind SSO, with password login off?",
    "why": "A local login skips MFA and is missed when someone leaves. Vendors say they support SSO in their SOC 2; this checks that we actually turned it on.",
    "sources": ["Vendor inventory", "Identity provider apps"],
    "frequency": "Daily",
    "response": "Password login switched back on for an SSO app is reverted automatically. Anything else opens a ticket for the app owner.",
    "frameworks": ["SOC 2 CC6.1", "ISO 27001 A.8.5", "NIST CSF PR.AA-03"],
}

IN_SCOPE_TIERS = (1, 2)


def check(state, today):
    findings = []
    tested = 0
    for vid, v in sorted(state["vendors"].items()):
        if v["status"] != "active" or v["tier"] not in IN_SCOPE_TIERS:
            continue
        if date.fromisoformat(v["contract_end"]) < today:
            continue  # ended vendors belong to CCM-04
        tested += 1
        app = state["idp_apps"].get(v.get("app") or "")
        if app is None or not app["active"]:
            findings.append({
                "key": f"CCM-01:{vid}:no-idp",
                "title": f"{v['name']} is not connected to the identity provider",
                "severity": "High",
                "evidence": {"vendor": v["name"], "tier": v["tier"], "data": v["data"], "idp_app": None},
                "fix": f"Create the SSO app for {v['name']}, move users over, then turn off password login.",
            })
            continue
        if not app["sso_enforced"]:
            findings.append({
                "key": f"CCM-01:{vid}:not-enforced",
                "title": f"{v['name']} allows sign in without SSO",
                "severity": "High",
                "evidence": {"vendor": v["name"], "idp_app": v["app"], "sso_enforced": False, "password_login": app["password_login"]},
                "fix": f"Turn on SSO enforcement for {v['name']} and remove local accounts.",
            })
        elif app["password_login"]:
            findings.append({
                "key": f"CCM-01:{vid}:password-login",
                "title": f"Password login was switched back on for {v['name']}",
                "severity": "Critical",
                "evidence": {"vendor": v["name"], "idp_app": v["app"], "sso_enforced": True, "password_login": True},
                "fix": "Reverted automatically. Ask the admin who changed it whether a break glass account is needed.",
                # Safe to undo on our own: SSO already works for everyone.
                "auto_fix": [{"op": "set", "path": ["idp_apps", v["app"], "password_login"], "value": False}],
            })
    return tested, findings

CCM-02 · Daily

User access drift

Does anyone still have vendor app access they should not?

Offboarding usually removes SSO, but local accounts and admin rights inside vendor apps drift. Quarterly access reviews find this months later; a daily diff finds it the next morning.

Reads
HR system, Vendor app user lists, Approved admin list
When it fails
Opens a ticket for the app owner with the account and the reason. Never removes access on its own, because the owner may need to move data first.
Maps to
SOC 2 CC6.2SOC 2 CC6.3ISO 27001 A.5.18NIST CSF PR.AA-05
See the check access_drift.py
"""CCM-02 User access drift.

Compares every vendor app's user list with the HR system. Flags accounts that
belong to people who left, contractors past their end date, and admin rights
that were never approved.
"""

from datetime import date

CONTROL = {
    "id": "CCM-02",
    "name": "User access drift",
    "question": "Does anyone still have vendor app access they should not?",
    "why": "Offboarding usually removes SSO, but local accounts and admin rights inside vendor apps drift. Quarterly access reviews find this months later; a daily diff finds it the next morning.",
    "sources": ["HR system", "Vendor app user lists", "Approved admin list"],
    "frequency": "Daily",
    "response": "Opens a ticket for the app owner with the account and the reason. Never removes access on its own, because the owner may need to move data first.",
    "frameworks": ["SOC 2 CC6.2", "SOC 2 CC6.3", "ISO 27001 A.5.18", "NIST CSF PR.AA-05"],
}


def check(state, today):
    findings = []
    tested = 0
    people = state["hris"]
    for app_id, users in sorted(state["app_users"].items()):
        vendor = next((v for v in state["vendors"].values() if v.get("app") == app_id), None)
        if vendor is None or vendor["status"] != "active":
            continue  # ended vendors belong to CCM-04
        approved = set(state["approved_admins"].get(app_id, []))
        for email, acct in sorted(users.items()):
            tested += 1
            person = people.get(email)
            base = {"app": vendor["name"], "account": email, "role": acct["role"]}
            if person is None:
                findings.append({
                    "key": f"CCM-02:{app_id}:{email}:unknown",
                    "title": f"{email} in {vendor['name']} is not in the HR system",
                    "severity": "High",
                    "evidence": {**base, "hr_record": None},
                    "fix": "Find who owns the account. Remove it or link it to a named person.",
                })
            elif person["status"] == "terminated":
                findings.append({
                    "key": f"CCM-02:{app_id}:{email}:left",
                    "title": f"{person['name']} left on {person['end_date']} but still has {vendor['name']}",
                    "severity": "High",
                    "evidence": {**base, "hr_status": "terminated", "end_date": person["end_date"]},
                    "fix": f"Remove the {vendor['name']} account and check its last sign in.",
                })
            elif person["type"] == "contractor" and person.get("end_date") and date.fromisoformat(person["end_date"]) < today:
                findings.append({
                    "key": f"CCM-02:{app_id}:{email}:contract-ended",
                    "title": f"Contractor {person['name']} ended {person['end_date']}, {vendor['name']} access still active",
                    "severity": "High",
                    "evidence": {**base, "type": "contractor", "end_date": person["end_date"]},
                    "fix": "Remove access, or get the contract extension and update the end date in HR.",
                })
            elif acct["role"] == "admin" and email not in approved:
                findings.append({
                    "key": f"CCM-02:{app_id}:{email}:unapproved-admin",
                    "title": f"{person['name']} is an admin in {vendor['name']} without approval",
                    "severity": "Medium",
                    "evidence": {**base, "approved_admins": sorted(approved)},
                    "fix": "Approve it with a reason, or drop the account back to a standard user.",
                })
    return tested, findings

CCM-03 · Daily

Shadow vendors

Are there apps reading company data that never went through vendor review?

One click on Allow gives a new AI tool read access to someone's Drive. That is a new vendor with no assessment, no contract and no exit plan.

Reads
Google Workspace OAuth grants, Vendor inventory
When it fails
Opens a vendor intake ticket and messages the users who granted it. Blocking the app is a decision for the risk owner.
Maps to
SOC 2 CC9.2ISO 27001 A.5.19NIST CSF GV.SC-04
See the check shadow_vendors.py
"""CCM-03 Shadow vendors.

Any app a user connects to Google Workspace with access to mail, files or the
directory is a vendor holding company data. If it is not in the vendor
inventory, nobody has assessed it.
"""

CONTROL = {
    "id": "CCM-03",
    "name": "Shadow vendors",
    "question": "Are there apps reading company data that never went through vendor review?",
    "why": "One click on Allow gives a new AI tool read access to someone's Drive. That is a new vendor with no assessment, no contract and no exit plan.",
    "sources": ["Google Workspace OAuth grants", "Vendor inventory"],
    "frequency": "Daily",
    "response": "Opens a vendor intake ticket and messages the users who granted it. Blocking the app is a decision for the risk owner.",
    "frameworks": ["SOC 2 CC9.2", "ISO 27001 A.5.19", "NIST CSF GV.SC-04"],
}

# Scopes that reach company data. Calendar free/busy and sign in only do not count.
SENSITIVE = {
    "gmail.readonly": "read all mail",
    "gmail.modify": "read and change mail",
    "drive": "read and change all Drive files",
    "drive.readonly": "read all Drive files",
    "admin.directory.user.readonly": "read the staff directory",
}


def check(state, today):
    known = {v["oauth_client"] for v in state["vendors"].values() if v.get("oauth_client") and v["status"] == "active"}
    findings = []
    tested = 0
    for client, g in sorted(state["oauth_grants"].items()):
        tested += 1
        risky = [s for s in g["scopes"] if s in SENSITIVE]
        if not risky or client in known:
            continue
        findings.append({
            "key": f"CCM-03:{client}",
            "title": f"{g['app']} can {SENSITIVE[risky[0]]} and is not a reviewed vendor",
            "severity": "High" if len(g["users"]) > 1 or "gmail" in risky[0] else "Medium",
            "evidence": {"app": g["app"], "client_id": client, "scopes": risky, "granted_by": g["users"], "first_grant": g["granted"]},
            "fix": f"Start vendor intake for {g['app']}. If it is rejected, revoke the grant for all users.",
        })
    return tested, findings

CCM-04 · Daily

Vendor offboarding

When a vendor contract ends, is every connection to them actually closed?

Contracts end in the procurement system. API keys and SSO apps live somewhere else, so they keep working long after anyone remembers the vendor.

Reads
Vendor inventory (contract dates), Identity provider apps, Vendor app user lists, API key register, Google Workspace OAuth grants
When it fails
Opens one ticket per vendor listing everything still connected, and updates it as items close.
Maps to
SOC 2 CC9.2ISO 27001 A.5.22NIST CSF GV.SC-10
See the check offboarding.py
"""CCM-04 Vendor offboarding.

When a vendor contract ends, everything that connects us to them should be
gone: the SSO app, user accounts, API keys and OAuth grants.
"""

from datetime import date

CONTROL = {
    "id": "CCM-04",
    "name": "Vendor offboarding",
    "question": "When a vendor contract ends, is every connection to them actually closed?",
    "why": "Contracts end in the procurement system. API keys and SSO apps live somewhere else, so they keep working long after anyone remembers the vendor.",
    "sources": ["Vendor inventory (contract dates)", "Identity provider apps", "Vendor app user lists", "API key register", "Google Workspace OAuth grants"],
    "frequency": "Daily",
    "response": "Opens one ticket per vendor listing everything still connected, and updates it as items close.",
    "frameworks": ["SOC 2 CC9.2", "ISO 27001 A.5.22", "NIST CSF GV.SC-10"],
}


def check(state, today):
    findings = []
    tested = 0
    for vid, v in sorted(state["vendors"].items()):
        ended = v["status"] == "offboarded" or date.fromisoformat(v["contract_end"]) < today
        if not ended:
            continue
        tested += 1
        open_items = []
        app = state["idp_apps"].get(v.get("app") or "")
        if app and app["active"]:
            open_items.append(f"SSO app {v['app']} still active")
        users = state["app_users"].get(v.get("app") or "", {})
        if users:
            open_items.append(f"{len(users)} user accounts")
        keys = [k for k, key in state["api_keys"].items() if key["vendor"] == vid and key["active"]]
        open_items += [f"API key {k} active" for k in keys]
        if v.get("oauth_client") in state["oauth_grants"]:
            open_items.append("OAuth grant in Google Workspace")
        if open_items:
            findings.append({
                "key": f"CCM-04:{vid}",
                "title": f"{v['name']} contract ended {v['contract_end']} but is still connected",
                "severity": "High" if keys or v["data"] == "Confidential" else "Medium",
                "evidence": {"vendor": v["name"], "contract_end": v["contract_end"], "still_open": open_items},
                "fix": "Revoke the keys first, then deactivate the SSO app and remove accounts. Ask the vendor for data deletion confirmation.",
            })
    return tested, findings

Next

Back to the GRC Lab