Whether secret scanning, push protection and validity checking are switched on in this organization and which repositories those settings actually reach, together with the alerts themselves — each carrying the kind of credential found, whether the credential was confirmed to still work, how it was closed and by whom, and whether a push containing it was blocked or waved through. The settings are the population; the alerts are what was found in it, and an alert list read without the settings beside it cannot be told apart from a list produced by scanning nothing.
The API supplies the facts, but a human judgement against a documented baseline turns them into evidence.
Fetch
$ gh api --paginate "/orgs/<ORG>/code-security/configurations"$ gh api --paginate "/orgs/<ORG>/code-security/configurations/<CONFIGURATION_ID>/repositories?per_page=100"$ gh api --paginate "/orgs/<ORG>/secret-scanning/alerts?state=open&per_page=100"$ gh api --paginate "/orgs/<ORG>/secret-scanning/alerts?state=resolved&per_page=100"Expected output
Report names used below, and the command each comes from: `configurations` is the first command, `configuration-repositories` the second, `alerts-open` the third, `alerts-resolved` the fourth. RUN THE SECOND COMMAND ONCE PER CONFIGURATION returned by the first, not once for the organization. The first returns every configuration and the second takes a single `<CONFIGURATION_ID>`; the clause on `configuration-repositories` speaks only for the configurations actually walked. From the configurations call, an array of code security configurations, each with an id, a name, a `target_type` of `global`, `organization` or `enterprise`, and the secret-scanning feature fields as THREE-STATE strings rather than booleans — `secret_scanning`, `secret_scanning_push_protection`, `secret_scanning_validity_checks`, `secret_scanning_non_provider_patterns`, `secret_scanning_delegated_bypass` and `secret_scanning_delegated_alert_dismissal` each taking `enabled`, `disabled` or `not_set` — plus an `enforcement` of `enforced` or `unenforced`. `not_set` is the value that defeats a careless clause: it is neither on nor off, it is the absence of a decision, and a comparison against `disabled` alone walks straight past it. From the configuration-repositories call, rows carrying a `status` of `attached`, `attaching`, `detached`, `removed`, `enforced`, `failed`, `updating` or `removed_by_enterprise`. From the alerts calls, alerts with `number`, `created_at`, `updated_at`, `url`, `html_url`, a `state` of `open` or `resolved`, a `resolution` drawn from `false_positive`, `wont_fix`, `revoked`, `used_in_tests`, `pattern_edited` and `pattern_deleted`, `resolved_at` and `resolved_by`, a `secret_type` and its `secret_type_display_name`, a `validity` of `active`, `inactive` or `unknown`, and the push-protection quartet `push_protection_bypassed`, `push_protection_bypassed_by`, `push_protection_bypassed_at` and — for the alert raised by the bypass — the repository it landed in, plus `publicly_leaked` and `multi_repo`. Note that `resolution` and `validity` are documented as comma-separated FILTERS accepting those values as well as fields carrying them, and that the endpoint takes `secret_type`, `exclude_secret_types`, `providers`, `sort`, `direction`, `before`, `after`, `is_publicly_leaked` and `is_multi_repo` besides. The organization endpoint requires an administrator or a security manager, and a token carrying the `repo` or `security_events` scope.
Assertions — what makes it a pass
| Field | Must be | For | Proves |
|---|---|---|---|
| configurations[?target_type=='organization' && secret_scanning=='enabled'] | [0].id | existsAt least one code security configuration the organization itself owns sets `secret_scanning` to `enabled`. Three-state field, so the middle value is the trap: `not_set` is the absence of a decision rather than a `no`, and a clause written against `disabled` passes an organization that never decided. `target_type` is narrowed to `organization` because the enum admits a `global` scope no administrator creates. This says a configuration exists and decided; it does not say which repositories it reaches, and a failure means no organization-owned configuration governs scanning — not that nothing is scanned. | every row | IA-05 (06) |
| configurations[?target_type=='organization' && secret_scanning_push_protection!='enabled'] | count_eq 0No configuration the organization owns leaves push protection unenabled. `!=` rather than `== 'disabled'` on purpose: the field is three-state and `not_set` is what a comparison against `disabled` misses. Written as an offender count over rows present in the same response the clause above reads, rather than as a projection over the rows that already carry the setting, which would be green on a list where every configuration has it off. Detection after the fact and prevention at the push are different protections, and this is the only clause here that asks for the second. | every row | IA-05 (06) |
| configurations[?target_type=='organization' && secret_scanning_validity_checks!='enabled'] | count_eq 0No configuration the organization owns leaves validity checking unenabled. This clause exists to give the next one a chance of meaning something — it is necessary and it is NOT sufficient. `validity` is `unknown` on every alert in an organization that never turned validity checks on, and `unknown` is not `active`, so the next clause passes perfectly while nothing has ever been checked. Green here does not make the next clause safe: unsupported secret types stay `unknown` with the feature fully on, checks are periodic rather than retroactive, and this clause reads configurations rather than the repositories the alerts came from. See the notes for all three residues. Red here makes the next clause unreadable rather than passing. | every row | IA-05 (06) |
| alerts-open[?validity=='active'] | count_eq 0No open secret scanning alert names a credential the issuing provider confirmed still works. This is the sharpest statement available on this plane about authenticator protection: not that a secret was committed, which is history, but that a committed secret is live now. It is not readable alone. It requires the first clause (scanning on at all) and the third (validity checking on) to be green, and it still passes over any secret type GitHub cannot validity-check and over any alert not yet re-checked since the feature was enabled. Offender form over a state-filtered list, and its silence is bounded once more by the partner programme: a leaked credential handled directly with its vendor never appears here at all. | every row | IA-05 (06) |
Authored opinion, like the commands. Units live in the operator name — max-age-days is days, and nothing here is converted for you.
Map — what it proves
- recipe1
- recipe— an authored recipe collects evidence for this control
- KSI only— a Key Security Indicator reaches it, but no recipe is authored yet
- orphan— no Key Security Indicator reaches it — a person writes it up instead
What else these families can fetch:IA 6/30 →
Outside the boundaryGitHub Enterprise Cloud
The detection engine, the alert store and the record of who bypassed a block are all held and operated by the platform, so collecting this evidence brings it into the assessment as an information resource under SA-09 and CA-03 and into the external-system inventory AC-20 already covers. The consequence is sharper here than on a scanning control, and it is worth stating plainly: this recipe hands a third party the authenticators themselves. Detection works by matching the credential, validity checking works by ASKING THE ISSUING PROVIDER whether it still works, and the partner programme works by reporting the match to the vendor who issued it. A provider adopting this is not only trusting the platform with its code; it is trusting it with the secrets that leaked out of it, and with the fact that they leaked. IA-05 (06) is a class c and class d control, so every reader of it runs a Moderate or High system, and the offering named above is not the one such a reader can necessarily use: the Marketplace listing cited below is the listing for GitHub Enterprise Cloud, and a class c or class d reader has to check it against the class they are operating at and, if it does not answer, look to whichever offering does — GitHub Enterprise Cloud for Government is a different product on different infrastructure and carries its own listing. That is the SA-09 question. It is answered by reading the listings rather than by this sentence, and no status value is written down here because a certification status is a dated fact that changes. Which offering is in use decides the rest: secret scanning for private and internal repositories requires GitHub Secret Protection on GitHub Team or GitHub Enterprise Cloud, and GitHub Enterprise Cloud, GitHub Enterprise Cloud with data residency and github.com are different deployments on different infrastructure. This recipe was authored against GitHub Enterprise Cloud.
Notes & assertions
IA-05 (06) asks the provider to protect authenticators commensurate with the security category of the information to which use of the authenticator permits access. Two words in that sentence are the reason this is `partial` and would stay `partial` under any amount of extra collection. PROTECT is broader than DETECT: this evidence is a detection-and-response record for one storage location, and the control asks about the protection of authenticators wherever they live. COMMENSURATE is a judgement that requires knowing what the credential opens, and no field in any response here says that — `secret_type` names the kind of credential, never the security category of what it unlocks. A `high` alert on a test-fixture token and a `low` alert on a production database password are the same shape in this output. The disposition this recipe spends said exactly that, and writing the commands down has not changed it. The population problem, stated once and load-bearing everywhere below. Authenticators live in secret stores, CI variable sets, container images, build arguments, configuration management and on operator workstations. This recipe reads git repositories on one platform. The fraction of the provider's authenticator population that is in scope here is not a number this recipe can compute, and `scan_scope` names the external list against which somebody has to compute it. WHY THE VALIDITY CLAUSE IS INTERLOCKED WITH A SETTINGS CLAUSE, AND WHY THE INTERLOCK IS NECESSARY WITHOUT BEING SUFFICIENT. The fourth assertion asserts that no open alert has a `validity` of `active` — no leaked credential is confirmed to still work. Read alone it is one of the most vacuous clauses on this plane, because `validity` is `unknown` for every alert in an organization that never switched validity checks on, and `unknown` is not `active`, so the clause passes perfectly on an organization that has never checked a single credential. The third assertion exists to close that: it fails an organization whose configurations leave `secret_scanning_validity_checks` at anything other than `enabled`. What it does NOT do is make the fourth clause safe, and an earlier draft of this paragraph claimed it did. Three residues survive it. First, GitHub documents that validity checks are "available for secrets from many service providers, and support continues to expand" and that "Some secrets require more than the token itself to confirm whether they are active" — so a leaked credential of an unsupported type reports `unknown` with validity checking fully enabled, and the fourth clause passes over it. Second, GitHub "will periodically check the validity of a detected credential", which is a schedule rather than a trigger: enabling the feature does not retro-populate the alerts already open, so there is a window after enablement in which every existing alert is still `unknown`. Third, the third clause is not even the only prerequisite — the FIRST assertion is equally load-bearing, because with `secret_scanning` off there are no alerts of any validity at all and the fourth clause is vacuous for a reason the third never touches. And the third clause reads configurations rather than repositories, so it can be red while validity checking is genuinely on through repository-level settings, and green while the repositories that matter are attached to no configuration at all; it does not bind the population the alerts came from. Read the fourth clause as meaningful only when the first and third are green AND the reconciliation in `scan_scope` has been done, and read a green fourth clause on its own as saying nothing. THE PARTNER PROGRAMME IS AN INVISIBLE SUCCESS PATH AND IT MAKES AN EMPTY ALERT LIST AMBIGUOUS IN A NEW DIRECTION. GitHub states that "Partner secrets are reported directly to the provider and aren't displayed in your repository alerts". So for a leaked credential issued by a participating vendor, the platform's response is to tell the vendor, and the provider's own alert list stays empty. An empty `alerts-open` is therefore equally an organization that has leaked nothing, an organization that is not scanning, and an organization whose leaks were all handled by a party that never told it. The first and third of those are indistinguishable in this output and only one of them is a pass. This is not the usual empty-list caveat imported from the plane card; it is a documented behaviour of this specific feature, and an assessment reading a clean alert list as evidence of a clean estate has made the exact error the platform's own documentation predicts. What the bypass fields are worth, and where they stop. Push protection blocks a push containing a detected credential, and GitHub documents that anyone with write access can bypass it by choosing a reason from "It's used in tests", "It's a false positive" and "I'll fix it later", after which the platform "Creates an alert", "Adds the bypass event to the audit log", and emails owners, security managers and repository administrators. So a bypass is a recorded decision rather than a silent one, and `push_protection_bypassed`, `push_protection_bypassed_by` and `push_protection_bypassed_at` on the resulting alert are that decision as fields. No clause below asserts a count of zero over them, deliberately: a bypass is a documented, authorized action with a named actor and a stated reason, and a provider with a legitimate test fixture would fail such a clause while behaving correctly. The bypass records are collected as a record for a human to read against the provider's own procedure — the third of the three documented reasons is an admission that a credential was pushed knowingly, and how long "later" ran is a question for the assessment rather than for a threshold. Delegated bypass, whose enablement is visible as `secret_scanning_delegated_bypass`, moves the decision to a reviewer; it is collected, not asserted, for the same reason. A code security configuration is not the only way any of this gets switched on, so the first three clauses are wrong in one direction. The features can be enabled on a repository directly in its own settings, with no configuration involved, and an organization that never adopted configurations returns an empty list from the first command and fails all three while scanning everything it owns. Read a failure as "no organization-level configuration governs this" — which is literally true and is itself a finding — and NOT as "nothing is scanned". The reconciliation named in `scan_scope` is what separates the two readings, and nothing in this output does. The `target_type` narrowing carries the same cost it carries on the dependency recipe: the enum admits `global` and `enterprise`, an administrator can apply a configuration owned elsewhere, and applying it is a decision this clause will not count. The trade is made the same way and for the same reason. KSI-SVC-ASM is claimed on the PROTECTION limb only. The indicator asks for management, protection and regular ROTATION of keys, certificates and other secrets, automated and persistently reviewed. Detection of an exposed secret, and the record of what was decided about it, is protection and it is review. Rotation is not a scanning result: `resolution` admits `revoked`, which is the closest this output comes, and it is a human's assertion typed into a dropdown rather than an observation that a credential was replaced. The rotation limb of this indicator is answered on the AWS plane, by the KMS and ACM recipes, and an indicator page carrying this recipe should be read as carrying evidence for a part. KSI-IAM-APM and KSI-IAM-ELP also reach this control in the dataset and are deliberately not claimed: one is about passwordless and phishing-resistant authentication methods and the other about least privilege, and a leaked-credential detector speaks to neither.
Scanned population
The repositories inside the authorization boundary, taken from the component inventory the provider maintains for CM-08 and enumerates in its Certification Package Overview — a list held OUTSIDE the platform. Every command here reads the platform's own view of itself, and the failing case is structurally invisible to all four: a repository that is in the boundary, was never attached to a code security configuration, and has secret scanning off in its own settings produces no configuration row, no repository row and no alert. It is absent, not false, and it is the repository most likely to be leaking. Reconciling the repository ids returned by the second command against that external inventory is the only step in this recipe that can see it. A second reconciliation is needed here that the dependency recipe did not need, because this control is about authenticators rather than about repositories: the places the provider's own key-management procedure says authenticators live — the secret store, the CI variable set, the image build args, the operator workstations — are a list this recipe cannot enumerate at all, and the fraction of that list which is `a git repository` is the fraction this evidence speaks for.
- configurations
- configuration-repositories
References
- GitHub REST: secret scanning — GET /orgs/{org}/secret-scanning/alerts and GET /repos/{owner}/{repo}/secret-scanning/alerts; state open | resolved, resolution false_positive | wont_fix | revoked | used_in_tests | pattern_edited | pattern_deleted, validity active | inactive | unknown, and the alert fields number, created_at, secret_type, secret_type_display_name, resolved_at, resolved_by, push_protection_bypassed / _by / _at, publicly_leaked and multi_repo; repo or security_events scope, organization endpoint requires an administrator or security manager https://docs.github.com/en/rest/secret-scanning/secret-scanning
- GitHub REST: code security configurations — the secret-scanning enablement fields secret_scanning, secret_scanning_push_protection, secret_scanning_validity_checks, secret_scanning_non_provider_patterns, secret_scanning_delegated_bypass and secret_scanning_delegated_alert_dismissal, each documented as enabled | disabled | not_set, and the repository association status enum attached | attaching | detached | removed | enforced | failed | updating | removed_by_enterprise https://docs.github.com/en/rest/code-security/configurations
- GitHub: about secret scanning — scans "your entire Git history on all branches" for hardcoded credentials; "Partner secrets are reported directly to the provider and aren't displayed in your repository alerts"; validity checks "help you prioritize which secrets to remediate first by verifying whether a detected secret is still active" and are "separate from secret scanning's partner program"; private and internal repositories require GitHub Secret Protection on GitHub Team or GitHub Enterprise Cloud https://docs.github.com/en/code-security/secret-scanning/introduction/about-secret-scanning
- GitHub: about push protection — blocks the push and "provide[s] a detailed message explaining the reason for the block"; "Anyone with write access to the repository can bypass push protection by specifying a bypass reason" from used-in-tests, false-positive and I'll-fix-it-later; a bypass "Creates an alert", "Adds the bypass event to the audit log" and emails owners, security managers and repository administrators; delegated bypass moves the decision to a reviewer; requires GitHub Secret Protection https://docs.github.com/en/code-security/secret-scanning/introduction/about-push-protection
- FedRAMP Marketplace: GitHub Enterprise Cloud — the listing to re-read rather than quote, and the place to check the impact level against the class c and class d systems IA-05 (06) applies to; a certification status is a dated fact about a product, not about your deployment, and this recipe hands that product the authenticators themselves https://www.fedramp.gov/marketplace/products/FR1812058188/
This pipeline mapping is authored opinion (overlay v0.8.0), versioned separately from the dataset and written against ruleset 2026.07.14.01. The upstream FedRAMP dataset names none of these tools.
The Service Configuration run (10)
- automatable
- partial — needs judgement
- narrative — no API proves this
Every authored recipe filed under SVC, in the order the plan works them. The mark says how much of the evidence the command produces on its own.
- partialAWS Config compliance results across the storage services proving customer data is encrypted at rest — S3 buckets with default server-side encryption, EBS volumes encrypted, and RDS storage encrypted, all backed by KMScontinuousconfig-encryption-at-restAWS Config · Amazon S3 · Amazon EBS · Amazon RDS · AWS KMS
- partialAWS Config compliance results proving data in transit is protected by TLS — S3 bucket policies denying non-TLS requests, load-balancer listeners restricted to SSL/HTTPS, and Redshift clusters requiring SSLcontinuousconfig-encryption-in-transitAWS Config · Amazon S3 · Elastic Load Balancing · Amazon Redshift
- partialAWS Config compliance results proving KMS customer-managed keys are lifecycle-managed — automatic annual rotation enabled and no active key scheduled for deletion — the key-hygiene half of the cryptographic-protection controlcontinuousconfig-kms-key-managementAWS Config · AWS KMS
- partialAWS Config compliance results plus the State Manager association list proving a defined configuration is actually applied and re-applied to every managed node — instances are under SSM management, and the associations that carry your baseline report COMPLIANT on a schedule rather than driftingcontinuousssm-configuration-baseline-enforcedAWS Config · AWS Systems Manager
- partialCryptographic proof that the audit trail CloudTrail delivered has not been altered or deleted, plus the compliance state of the write-once controls that make stored records and container images tamper-evidentweeklyintegrity-verification-and-immutabilityAWS CloudTrail · AWS Config · Amazon S3 · AWS Backup · Amazon ECR
- partialDNSSEC signing status of every public hosted zone, with the key-signing key state and the DS record that carries the chain of trust to the parentweeklyroute53-dnssec-signingAmazon Route 53 · AWS KMS
- partialPer-VPC DNSSEC validation status of the Route 53 Resolver, joined against the full VPC inventory so that a VPC which never enabled validation is visible rather than absentweeklyroute53-resolver-dnssec-validationAmazon Route 53 · Amazon VPC
- partialEvery place a client session terminates, with the protocol and negotiated policy it terminates under: listener protocol and SslPolicy on each load balancer, HTTP listeners that redirect rather than serve, an ACM certificate behind each one, and CloudFront viewer policies that refuse plain HTTPquarterlysession-authenticity-tls-terminationElastic Load Balancing · Amazon CloudFront · AWS Certificate Manager · AWS Config
- partialThe hosted zones that serve name resolution, each marked private or public so internal and external resolution can be shown to be served by separate zones, and the Resolver endpoints that carry queries across the VPC boundary with their direction and operational statuscontinuousname-resolution-role-separationAmazon Route 53 · Amazon Route 53 Resolver
- partialWhether secret scanning, push protection and validity checking are switched on in this organization and which repositories those settings actually reach, together with the alerts themselves — each carrying the kind of credential found, whether the credential was confirmed to still work, how it was closed and by whom, and whether a push containing it was blocked or waved through. The settings are the population; the alerts are what was found in it, and an alert list read without the settings beside it cannot be told apart from a list produced by scanning nothing.you are herecontinuoussecret-exposure-detection-and-push-protectionGitHub secret scanning · GitHub code security configurations