Conformance Check Failure
Check ID: SEC-005 (Cross-Repository Validation)
Severity: HIGH
Category: Security
Problem Description
The update_activation_comment.cjs handler accepts a caller-supplied options.targetRepo value ("owner/repo") and uses it to create a fallback comment in that repository, but it does not validate the target repository against a configured allowlist. SEC-005 requires that any safe-output handler supporting cross-repository writes validate the target repo against an allowlist before performing the API call, to prevent a workflow from being steered into writing comments to arbitrary repositories.
Every other cross-repo handler in actions/setup/js/ (e.g. add_comment.cjs, add_labels.cjs, assign_milestone.cjs) already routes its target-repo resolution through the canonical allowlist helpers in repo_helpers.cjs. This handler is the outlier.
Affected Components
- Files:
actions/setup/js/update_activation_comment.cjs
- Handlers:
update_activation_comment (cross-repo fallback comment path)
- Canonical helpers:
actions/setup/js/repo_helpers.cjs (resolveTargetRepoConfig, resolveAndValidateRepo)
🔍 Current vs Expected Behavior
Current Behavior
In the standard-mode fallback path (update_activation_comment.cjs, around lines 194-210), options.targetRepo is split into fallbackOwner/fallbackRepo and passed straight to the GitHub API:
if (options.targetRepo) {
const parts = options.targetRepo.split("/");
if (parts.length === 2) {
fallbackOwner = parts[0];
fallbackRepo = parts[1];
}
}
const fallbackClient = options.targetGithubClient || github;
// ...
await fallbackClient.request("POST /repos/{owner}/{repo}/issues/{issue_number}/comments", {
owner: fallbackOwner,
repo: fallbackRepo,
// ...
});
There is no check that fallbackOwner/fallbackRepo is an allowed target before the write.
Expected Behavior
SEC-005 requires the handler to either:
- Validate
targetRepo against the configured allowlist (allowedRepos) using the shared helpers before issuing the API call, matching the pattern in add_comment.cjs; or
- If this handler is genuinely exempt because
targetRepo/targetGithubClient are always derived internally from already-validated context (never from agent-controlled output), document that with a @safe-outputs-exempt SEC-005 annotation and a justification comment.
Remediation Steps
This task can be assigned to a Copilot coding agent:
- Review the cross-repo fallback path in
actions/setup/js/update_activation_comment.cjs (the if (options.targetRepo) block) and determine the provenance of options.targetRepo — is it ever derived from agent-controlled safe output, or is it always supplied internally from validated invocation context?
- If it can carry agent-influenced values: import
resolveTargetRepoConfig and resolveAndValidateRepo from repo_helpers.cjs and validate targetRepo against allowedRepos before the POST .../comments request, mirroring add_comment.cjs (see lines 378-452 there). Reject or fall back safely when the repo is not allowed.
- If it is genuinely internal-only: add a top-of-file
@safe-outputs-exempt SEC-005 annotation with a one-line justification explaining why allowlist validation is unnecessary (so the checker skips it intentionally rather than silently).
- Add or extend a unit test asserting that an out-of-allowlist
targetRepo is rejected (or that the exemption invariant holds).
Verification
After remediation, verify the fix by running:
bash scripts/check-safe-outputs-conformance.sh
The SEC-005 check should pass: [PASS] SEC-005: All cross-repo handlers validate allowlists.
References
- Safe Outputs Specification:
docs/src/content/docs/reference/safe-outputs-specification.md
- Conformance Checker:
scripts/check-safe-outputs-conformance.sh (SEC-005, lines 165-193)
- Canonical allowlist helpers:
actions/setup/js/repo_helpers.cjs
- Reference implementation:
actions/setup/js/add_comment.cjs
- Run ID: 26705913294
- Date: 2026-05-31
Generated by ✅ Daily Safe Outputs Conformance Checker · opus48 526.1K · ◷
Conformance Check Failure
Check ID: SEC-005 (Cross-Repository Validation)
Severity: HIGH
Category: Security
Problem Description
The
update_activation_comment.cjshandler accepts a caller-suppliedoptions.targetRepovalue ("owner/repo") and uses it to create a fallback comment in that repository, but it does not validate the target repository against a configured allowlist. SEC-005 requires that any safe-output handler supporting cross-repository writes validate the target repo against an allowlist before performing the API call, to prevent a workflow from being steered into writing comments to arbitrary repositories.Every other cross-repo handler in
actions/setup/js/(e.g.add_comment.cjs,add_labels.cjs,assign_milestone.cjs) already routes its target-repo resolution through the canonical allowlist helpers inrepo_helpers.cjs. This handler is the outlier.Affected Components
actions/setup/js/update_activation_comment.cjsupdate_activation_comment(cross-repo fallback comment path)actions/setup/js/repo_helpers.cjs(resolveTargetRepoConfig,resolveAndValidateRepo)🔍 Current vs Expected Behavior
Current Behavior
In the standard-mode fallback path (
update_activation_comment.cjs, around lines 194-210),options.targetRepois split intofallbackOwner/fallbackRepoand passed straight to the GitHub API:There is no check that
fallbackOwner/fallbackRepois an allowed target before the write.Expected Behavior
SEC-005 requires the handler to either:
targetRepoagainst the configured allowlist (allowedRepos) using the shared helpers before issuing the API call, matching the pattern inadd_comment.cjs; ortargetRepo/targetGithubClientare always derived internally from already-validated context (never from agent-controlled output), document that with a@safe-outputs-exempt SEC-005annotation and a justification comment.Remediation Steps
This task can be assigned to a Copilot coding agent:
actions/setup/js/update_activation_comment.cjs(theif (options.targetRepo)block) and determine the provenance ofoptions.targetRepo— is it ever derived from agent-controlled safe output, or is it always supplied internally from validated invocation context?resolveTargetRepoConfigandresolveAndValidateRepofromrepo_helpers.cjsand validatetargetRepoagainstallowedReposbefore thePOST .../commentsrequest, mirroringadd_comment.cjs(see lines 378-452 there). Reject or fall back safely when the repo is not allowed.@safe-outputs-exempt SEC-005annotation with a one-line justification explaining why allowlist validation is unnecessary (so the checker skips it intentionally rather than silently).targetRepois rejected (or that the exemption invariant holds).Verification
After remediation, verify the fix by running:
The SEC-005 check should pass:
[PASS] SEC-005: All cross-repo handlers validate allowlists.References
docs/src/content/docs/reference/safe-outputs-specification.mdscripts/check-safe-outputs-conformance.sh(SEC-005, lines 165-193)actions/setup/js/repo_helpers.cjsactions/setup/js/add_comment.cjs