DEV Community

ke jia
ke jia

Posted on

The 5-Minute Audit That Replaces the Quarterly Security Review

The five minutes is the audit, and the audit is what the quarterly review becomes, because the becoming is the ritual, the ritual is what the five minutes allow, and the allowing is what the habit holds. The quarterly review is the meeting. The meeting is the deck. The deck is where the finding is summarized, and the summarizing is where the detail is lost, and the lost is what the scan does not lose, because the scan's detail is the report, and the report is the file and the line.
The ritual has five steps, and the five steps are the section below. The first is the scan, and the scan is the findings. The second is the verify, and the verify is the five-second check, and the check is what separates the real from the fixture. The third is the rotate, and the rotate is what the real finding becomes the dead key. The fourth is the re-scan, and the re-scan is what the dead is proven. The fifth is the note, and the note is the record, and the record is what the next quarter compares against. The quarterly review is what the ritual replaces, and the replacing is what the meeting becomes the confirmation instead of the discovery, because the discovery is what the ritual does in the five minutes, and the five minutes is what the meeting does not have.

The security section reads like an audit, because it is one: the asset, the threat, the control, and the residual risk, in that order, and the order is the part the fear-based security writing skips, because the skip is what makes the fear do the arguing. The asset here is the data the workflow touches, and the touches is the part that dotguard changes, because the changes is Scan .env files, config files, and source code for exposed secrets. Zero dependencies, JSON reports, 1000+ files in seconds.. The threat is the specific one for this workflow, and the specific is the part the section names before it names the control, because the named threat is what the control answers. The residual risk is stated at the end, because the stated residual is the part that makes the rest of the section the honest one.

How the Scan Actually Works

The scanner looks for the patterns that real secrets actually take. Cloud provider keys start with a known prefix, Git tokens start with a known prefix, messaging platform tokens have a known shape, payment processor live keys have a known prefix, and web tokens start with a known base64 header. It also checks for high-entropy strings assigned to suspicious variable names — password, token, secret, key — because the values do not always follow the format, but variable names are a reliable signal. The scan covers environment files, config files, and source code, and it reports the file, the line, and the matched pattern so a human can verify in seconds rather than minutes. It is deliberately a detection tool, not a verdict tool: it finds candidates, a human confirms, and the key gets rotated either way. That division of labor is what keeps false positives from becoming noise fatigue.

Two Rhythms: The Daily Path and the Quarterly Tree

The scanner runs on two cadences, and the two cadences are the practice. The daily one is the targeted scan: the path pointed at the directory that changed, the service that touched the config, the deploy folder that holds the real credentials. The targeted scan is fast enough to run before the push, and the fast is what makes it the reflex. The quarterly one is the recursive sweep: the flag pointed at the whole projects directory, the tree that includes the forgotten experiment and the demo repository and the fork that nobody maintains. The sweep is the deep clean, and the deep clean is what catches the leak that is already old, because the old leak is the one the targeted scan never points at, and the never-pointed-at is where the leak waits. The same command, the same rules, two scopes, two rhythms. The monorepo does not need a different tool for the two cadences, it needs the same tool aimed at the two scopes, and the aiming is the practice, and the practice is what the scanner's flags exist to make cheap.

False Positives Are the Real Cost of a Scanner

Every secret scanner has to make a tradeoff: miss a real key, or flag a false one. The scanner leans toward flagging, and the price is occasional false positives — an encoded blob that looks like a key, a test fixture with a fake credential, a documentation example that uses a real-looking prefix. That is why the output includes the file, the line, and the matched rule: the cost of verifying a finding should be five seconds, not a forensic exercise. A scanner with zero false positives that also misses real keys is a liability, not a tool. Budget a minute per finding, verify, rotate if it is real, and note the known test values so the team stops re-checking them. The loop is the product. Over time the false-positive list becomes its own artifact — a record of the places in the codebase that look like secrets and are not, which is useful information in its own right, because it maps the codebase's sensitive-looking surfaces.

One Line in GitHub Actions

The entire CI integration is one step: a run line that invokes the scanner via npx. No service container, no token to configure, no daemon. Every push gets a full scan, and the build fails if a secret is found, which means the secret never reaches the default branch. The beauty of the one-line integration is the maintenance cost: there is nothing to update, no version to pin, and no vendor to renew. When a security control costs one line of workflow file, the only question is why it is not already there. That is the bar every pre-merge security control should meet, and the scanner was designed to meet it on purpose. The one line is also the onboarding story: new contributors see the check in the workflow file, understand what it is doing, and never have to be told to run it. The pipeline is the policy, and the policy is one line long.

Five Seconds to Verify a Finding

The verification is the step that turns the finding into a decision, and the five seconds is the design target, because the five seconds is what keeps the check happening. The report gives the file, the line, and the rule, and the verification is open the file, look at the line, and answer one question: is this value live, or is it a fixture? The live value is the one that the build reads, that the deploy uses, or that a request would present to a real service. The fixture is the one that the test asserts against, that the README shows as an example, that the mock returns. The answer changes the next step: live means rotate and re-scan, fixture means note it and move on. The five seconds works because the report is specific, and the specificity is the feature. A scanner that says suspicious content found is a scanner that takes an hour to triage, and the hour is what stops the habit. The five seconds is the habit.

Secrets Hide in Unlikely Places

The environment file is where people look, and it is where secrets are least well hidden. The real distribution is wider: a database URL inside a container compose file, an API key in a YAML config under a deploy directory, a webhook token in a JSON file checked in for one test, a token pasted into a README as a working example. The scanner covers source code, not just dotfiles, precisely because the pattern of where secrets actually live is messier than the pattern of where people think they live. If your security review only opens environment files, you are reviewing one out of five places. The scanner's job is to make the review exhaustive by making it automatic, and the exhaustive part is the whole value. The surprising findings — the ones in files nobody would call secret files — are the ones that justify the tool, because they are the ones no checklist would ever reach. A checklist asks about secrets; the scanner asks about every file, which is a different and better question.

The Rotation Checklist the Report Triggers

The finding without the rotation is a list, and the list is the part that ages badly. The rotation checklist is the four steps that turn the finding into the closed loop, and the steps are short enough to be a habit. Step one is the verify, the five-second check that the value is live and not a fixture. Step two is the rotate, the call to the provider that replaces the key and invalidates the old one. Step three is the update, the new value in the place the build reads, and the old value deleted from everywhere the working tree still holds it. Step four is the re-scan, the same command run again, and the re-scan is the proof, because the proof is the old value not in the report. The four steps take the length of a coffee, and the coffee is the part that makes the loop close on the day of the finding instead of the day of the reminder. The report is the trigger, and the trigger without the loop is the notification, and the notification is what gets ignored.

Scanning the Worktree, and the History Behind It

The scanner covers what is on disk: the environment files, the config files, the source in your working tree. That catches the obvious case — the file you just created and are about to commit. For the subtler case, the secret that is already in history, you combine it with the version control system: find the files that ever contained the pattern, then scan them. A committed secret does not stop being a secret when it is deleted from the current branch; it lives in every clone, every fork, and every mirror. The honest workflow is two steps: scan the present automatically, and audit the past with the same rules applied to the files that history touched. Detection is a habit, and habits are easier to keep when the tooling is small enough to run by reflex. The present scan is the reflex; the past audit is the quarterly deep clean, and both use the same rules, which is what makes the pair coherent instead of two unrelated chores.

What Zero Dependencies Buys You in a Security Tool

A security tool has a special trust problem: you are asking it to read your most sensitive files. The natural question is what the tool itself trusts. For this one, the answer is nothing. No dependencies, no network calls, no telemetry, no update daemon. It reads files, matches patterns, and writes a report. That matters in the places where security tooling gets blocked: restricted CI runners, air-gapped builds, compliance environments that require an audit of every third-party package in the pipeline. A single-file scanner with zero dependencies is auditable in an afternoon by a security reviewer who would never approve a forty-package tree. In security, small is not a feature. Small is the product. The auditability is the trust model: you can read the whole thing, you can verify what it matches, and you can be confident that the thing reading your secrets is not also phoning home with them. That confidence is not a nice property of the design; it is the design.

The Exit Code Is the Integration

The scanner's interface to the machine is the exit code, and the exit code is the part that makes it CI-ready without any glue. A clean scan exits zero, a scan with findings exits nonzero, and the nonzero is what the pipeline turns into a failure, and the failure is what blocks the push. The pre-push hook uses the same code: the hook runs the scan, and the push goes through only if the exit code is zero. The JSON report is the second interface, for the things that consume data instead of pass/fail: the dashboard that charts findings over time, the chat alert that posts the file and the line, the compliance export that needs the record. The two interfaces cover the two consumers, the pipeline and the person, and the coverage is the design. A tool that needs a wrapper script to be useful in CI is a tool that will not be in CI, because the wrapper is the step that does not get written, and the not-written is the check that does not run.

What a Clean Scan Does for the Team

The clean scan is the output nobody celebrates, and the no-celebration is the point, because the clean scan is the state the team should be in by default. The value of the default-clean is the attention: the team's security attention goes to the findings, and the findings are the exceptions, and the exceptions are what get the rotate-today treatment instead of the quarter-review treatment. The clean scan also does the onboarding: the new developer who runs the scan and gets nothing learns the habit without the incident, and the habit learned without the incident is the habit that holds, because the first experience is the quiet one instead of the alarming one. The quiet is the design goal, and the quiet is what the pre-push hook and the CI gate buy, because the gate catches the leak before the team sees it, and the team that never sees the leak is the team that never has the incident meeting. The clean scan is the boring output, and the boring output is the expensive one to keep.

The takeaway

The security section ends where the architecture ends: at the boundary the tool does not cross. dotguard is Scan .env files, config files, and source code for exposed secrets. Zero dependencies, JSON reports, 1000+ files in seconds., installed with npx @wuchunjie/dotguard, source at https://github.com/wuchunjie00/dotguard. The boundary is the part the threat model respects, because the respects is the control, and the control is the part the residual risk is measured against. The reader who runs the tool runs the boundary, and the runs is the part the claim becomes the behavior, and the behavior is what the security section is for, because the for is the practice, and the practice is the habit with the check in it.

Top comments (0)