Guide 146 workflow

How to keep build artifacts and source out of security logs

Keep source and build artifacts out of security logs with typed, bounded fields, useful error categories and diagnostic checks that preserve operator visibility.

Keep source code and build artifacts out of security logs by defining a small, positive list of fields a scan may emit, then checking every path that can copy scanner output: worker logs, CI consoles, traces, error reports, notifications, tickets, and exported log streams. Record an opaque job ID, stage, outcome, counts, and a sanitized error category. Keep source-bearing evidence in a separately authorized, short-lived work area when it is needed at all. Test the boundary with a synthetic canary and review logger call sites; a redaction rule or a clean search alone cannot prove that every path is safe. The answer changes if an investigation genuinely requires a source excerpt: deliver it through an access-controlled evidence channel with an explicit retention rule, never as routine telemetry.

OWASP's Logging Cheat Sheet explicitly lists application source code, access tokens, passwords, connection strings, and keys among data that should usually be excluded, masked, or protected before logging. It also points out that copies can live in centralized repositories, archives, and backups. For a platform engineer, the practical question is where those copies arise in this scan path.

Illustrative incident: an error that copied a file into a log

Illustrative incident, not a customer event: Harbor Ledger runs a source scanner from a CI job. A parser fails on a configuration file. The worker catches the exception but logs the entire failed request object. That object includes a 30-line source window. The CI step captures worker standard error and uploads it as a troubleshooting artifact. The log collector also exports the event to a second account. No secret has been confirmed in those lines, but the source has already crossed three storage boundaries.

The response is not to hide the error. The useful event is: “scan J-82, parser stage, unsupported syntax, file category configuration, 1 file skipped, continuation available.” A reviewer can still diagnose scope and request a tightly scoped evidence session if authorized. The raw request object, source window, and exact exception payload are unnecessary for ordinary operations.

Surface Necessary signal Source-bearing failure to prevent
Worker event Opaque job and attempt IDs, stage, outcome, sanitized reason Request or model payload, source line, raw stack context
CI console Scan state, link to authorized result, bounded error code Shell tracing, scanner standard output, full file path or token
Trace and metric Duration, size bucket, stage, error class Source in span names, attributes, baggage, labels
Troubleshooting artifact Explicitly approved diagnostic metadata Automatic archive of work directory, cache, prompt or transcript
Notification or ticket Link and ownership information Raw evidence, secret, source excerpt or copied report

Even a path or repository name can disclose useful private information. Decide whether operational staff need it before allowing it into a general log. If they do, give it a classified field and access rule rather than appending it to an unrestricted message.

Map the actual log and artifact flow

Begin with one scan attempt and draw its outputs from source acquisition to deletion. Include the repository provider response, isolated work area, parser, model or other analysis call, CI wrapper, exception handler, log collector, alerting system, support tooling, and backup. For each edge, write the data class, destination, region, readers, retention, and owner. “Temporary” is not a retention answer unless the destination and failure path are named.

Inspect five common leak points:

  1. Diagnostic exceptions. Exception serializers can include request bodies, local variables, command arguments, HTTP headers, and snippets. Log a fixed error code and a generated correlation ID; keep a private diagnostic path only where justified.
  2. Standard output and shell options. A scanner may be quiet while a wrapper prints a command, environment, archive listing, or failed subprocess output. Turn off verbose and shell tracing in sensitive steps. Review what CI captures before changing the scanner itself.
  3. Model and tool traces. A prompt, retrieved file range, tool response, or model completion can be source-bearing. OpenTelemetry documents collector processors for deleting or allowlisting sensitive telemetry attributes. Filtering at capture is preferable to sending the text onward and masking it later.
  4. Artifact upload defaults. A broad workspace glob may include source copies, cached indexes, debug dumps, or raw reports. Specify exact artifact filenames and fail if an unexpected file appears. GitHub documents that workflow artifacts have independent removal and retention controls; log retention and artifact retention must both be checked.
  5. Downstream copies. Ticket automation, chat alerts, searchable log indexes, support exports, and backups may each have different readers and deletion times. A deletion in the worker cannot retract a copy already delivered elsewhere.

Build an allowlisted event schema, not a denylist of secret-looking strings. One usable schema is: event version, random job ID, tenant-safe routing token, stage name from a fixed enum, outcome, bounded counts, UTC timestamp, and error code from a fixed enum. Avoid free-form source text in message, attributes, and exception cause. Keep the detailed security finding in its intended access-controlled store. Validate the permitted fields too: a job identifier copied from repository text or an unbounded “count” can smuggle source through a schema whose field names look safe. Generate identifiers in the trusted service and enforce types, lengths and ranges before emission.

Verify with a safe canary and a negative path

Create an authorized synthetic repository, with a unique harmless marker in a configuration comment and a synthetic parser failure that exercises the suspected exception path. Do not use customer source or an actual credential. Run the same logging and artifact configuration used for the target environment without executing the repository's code, hooks, or dependencies. Search the authorized CI output, worker logs, traces, collector destination, uploaded artifacts, ticket previews, and relevant exported copies for the marker. Check both successful and failed scan paths, plus cancellation or timeout if those paths serialize different objects.

The canary tells you whether that exercised route leaked. It does not cover untested errors, every file type, every third-party processor, or historical copies. Pair it with a call-site review: search for raw exception printing, full-object serialization, HTTP body logging, prompt tracing, broad artifact globs, and logger statements that accept untrusted repository text. Record the exact artifact revision and configuration. Repeat after changes to CI, telemetry, error handling, or model integration.

Do not treat platform masking as the primary boundary. GitHub's secret reference describes automatic log redaction, but its coverage is defined by recognized values and patterns; arbitrary source code is not a registered secret. CloudWatch Logs data protection policies mask selected sensitive patterns at viewing and egress, while a principal with logs:Unmask can view matching underlying data. A nonmatching source excerpt may remain visible. Prevent ingestion first, then use masking as another control.

Inspect the event transformation, then the path it missed

The bad event in Harbor's synthetic case looks like this:

{"job":"J82","error":{"message":"parse failed","cause":{"source":"CANARY_SOURCE_82","path":"private/config.ts"}},"request":{"sourceWindow":"CANARY_SOURCE_82"}}

The replacement is constructed from approved values rather than by deleting a few known properties from the raw exception:

{"event_version":1,"job":"J82","attempt":"A2","stage":"parse","outcome":"partial","error_code":"UNSUPPORTED_SYNTAX","files_skipped":1,"continuation_available":true}

job and attempt connect operations without exposing a repository path. stage and error_code are fixed enums, not exception messages. The count and continuation flag preserve the fact that analysis is incomplete. There is no free-form cause object to acquire new sensitive fields in a later library release. An authorized evidence service can provide more detail if necessary; routine logs do not carry it by default.

The first canary exercise checks normal parser failure and finds no marker in worker output or the CI artifact. A cancellation branch then fails: it passes the original exception to a tracing helper, which serializes cause.source as a span attribute. These are invented exercise results to illustrate a review, not tests executed for this article.

The repair moves sanitization to the shared error-to-event boundary used by both logging and tracing. Cancellation emits outcome=canceled and a bounded reason code; it does not send the raw exception to another telemetry API. Collector filtering remains a second control, consistent with OpenTelemetry's sensitive-data guidance, but the source text should not reach the collector in the first place.

Evidence ledger after proposed repair Result assumed in this synthetic exercise Conclusion
Parser failure: worker and CI artifact Marker absent; partial status/count present Exercised path preserves useful failure visibility
Cancellation: trace and exported collector stream Marker absent after shared capture fix Original cancellation leak addressed in these destinations
Normal scan and timeout Not yet exercised Remain named validation work
Historical backup of earlier collector export Not directly inspectable by this reviewer Owner supplies retention/disposition evidence; no absence or erasure claim

The incident task for already ingested content remains open separately from the emission fix. Restrict readers, identify copied data and any credentials, preserve necessary evidence, and track every destination's disposition. CloudWatch masking is not deletion, and an absent canary in today's visible logs says nothing about yesterday's export backup.

The completed engineering handoff names the exact nested-cause path, the shared sanitizer, and the signals that must survive. It is much stronger than “enable redaction”: an operator still sees why a scan is partial, while the raw request and exception never enter routine telemetry.

Keep diagnosis useful after removing raw payloads

A source-free error event must still let an operator distinguish retryable infrastructure trouble from an unsupported input or a canceled job. Otherwise, support pressure will reintroduce raw payload logging as the quickest way to understand failures. In Harbor's design, maintain a small error catalogue that maps each stable code to its meaning, responsible component, retry policy and permitted diagnostic route. The catalogue contains product behavior, not examples copied from private repositories.

For UNSUPPORTED_SYNTAX, the operator needs the scan's partial state, skipped count and whether a narrower continuation is available. They do not need the parser's entire input buffer. For a temporary provider outage, they need the attempt identifier and retry outcome. If the engineering team truly needs one source excerpt, an authorized evidence request should identify the range, recipient, purpose and retention separately from ordinary log access.

Review field cardinality as part of the schema's meaning. A fixed error code is useful only if code cannot derive arbitrary values from an exception message. A file category should come from a controlled classification, not the private basename. The same rule applies when a library adds automatic span attributes: the capture boundary must construct an approved event rather than inherit every newly available field.

During rollout, compare operational usefulness as well as canary absence. Can an on-call engineer tell that the scan is partial? Can they locate the restricted result through the job identifier? Can they recognize a recurring parser defect without seeing source? If those answers are no, improve the safe fields or the evidence-access workflow. Do not solve the usability problem by broadly enabling verbose logging.

This review gives the source-exclusion rule an owner and a maintenance path. New parser, tracing and support integrations can be checked against an explicit diagnostic contract instead of rediscovering the same leak after each failure.

For the next scan integration, review one failure log and one uploaded artifact against the allowlisted schema before widening access. If the question is what a security vendor may receive in the first place, use the source-code exposure due-diligence checklist. For the credential side of the same workflow, continue with temporary tenant credential review.