Skip to main content

What the check does

Flags an actions/upload-artifact step with no retention-days: (or one above 90) in a workflow where the artifact is likely to carry something.

Why it matters

An uploaded artifact is a zip anyone with read access to the repository can download, for as long as it is retained — on a public repository, everyone. GitHub’s default retention is 90 days and an organisation can raise it to 400. So “we didn’t set it” and “we set it to the maximum” produce the same file sitting there for over a year. Build trees routinely contain more than the binary: a .env the build wrote, a signing key, a token in a config file, a coverage report naming internal hosts.

Why it does not fire on every upload

Most artifacts are a compiled binary nobody cares about. The rule fires where the artifact is likely to carry something:

Safe alternative

Set the shortest window that is actually useful. For an artifact a later job consumes minutes later, that is often 1:
And if the artifact may contain a token, a signing key, or a .env the build wrote — do not upload it at all. A short retention window on a leaked credential is still a leaked credential.

What does not fire

A limitation worth knowing

The risk is worst on a public repository, where “anyone with read access” means anyone at all. Repository visibility is not derivable from a workflow file — nothing in the YAML says whether the repo is public. Rather than guess, the rule gates on what the file does show. If your repository is public, treat every one of these findings as more urgent than its MEDIUM severity suggests.

Auto-fix

Partial. Adds retention-days: 90, creating the with: block if the step has none, guarded by a comment:
90 caps the artifact against an organisation default that may be 400. It is not the right answer for most artifacts, which is why the comment is part of the fix. Running it twice does not stack a second comment.