Redaction replaces sensitive values with markers before anything is shared. Structure stays so the question remains answerable.
Use unmistakable markers and remove sensitive values from the shared artifact. Replacement alone does not prove irreversibility: surrounding context, copies, encodings, and missed formats may retain information. Redaction does not change the sharing rules automatically.
Class | Marker | Sample count |
|---|---|---|
Credential assignments | [REDACTED] | 2 |
Bearer tokens | Bearer [REDACTED] | 2 |
Email addresses | [REDACTED-EMAIL] | 2 |
Internal hostnames | [REDACTED-HOST] | 2 |
The illustrative program below checks eight planted synthetic items plus one clean line. Its expected summary describes these fixtures only; no execution is claimed here. Regex patterns can miss multiline or encoded values, other field names, paths, IP addresses, and design information. Do not use this snippet as a production disclosure gate.
import re
import sys
CRED = re.compile(r"(?i)\b(password|passwd|api[_-]?key|secret)\s*[:=]\s*(\"[^\"]*\"|'[^']*'|\S+)")
BEARER = re.compile(r"Bearer\s+[A-Za-z0-9._~-]+")
HOST = re.compile(r"\b[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)*\.(internal|corp)(?![A-Za-z0-9-])")
EMAIL = re.compile(r"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}")
SAMPLES = [
'password = \"s3cr3t-demo-001\"',
"api_key: 'demo-key-002'",
"Authorization: Bearer alpha-003",
"Authorization: Bearer beta-004",
"contact alice@example-team.test",
"cc bob@example-team.test",
"ssh build-07.internal",
"nfs sim-03.corp",
]
SECRETS = [
"s3cr3t-demo-001",
"demo-key-002",
"alpha-003",
"beta-004",
"alice@example-team.test",
"bob@example-team.test",
"build-07.internal",
"sim-03.corp",
]
def redact(line):
total = 0
line, n = CRED.subn(r"\1=[REDACTED]", line)
total += n
line, n = BEARER.subn("Bearer [REDACTED]", line)
total += n
line, n = HOST.subn("[REDACTED-HOST]", line)
total += n
line, n = EMAIL.subn("[REDACTED-EMAIL]", line)
total += n
return line, total
def main():
total = 0
for i, s in enumerate(SAMPLES):
out, n = redact(s)
total += n
if n != 1:
print("FAIL: case " + str(i) + " redaction count is " + str(n))
return 1
if "[REDACTED" not in out:
print("FAIL: case " + str(i) + " marker absent")
return 1
if SECRETS[i] in out:
print("FAIL: case " + str(i) + " secret still present")
return 1
if total != 8:
print("FAIL: total count is " + str(total))
return 1
clean, n = redact("build passed with 0 warnings")
if n != 0 or clean != "build passed with 0 warnings":
print("FAIL: clean line changed")
return 1
print("PASS: fixture checks only; masked 8 planted items and left 1 clean line unchanged; sharing permission not established")
return 0
sys.exit(main())Each class contributes two planted items. The arithmetic below describes expected matches in these fixed fixtures, not measured detection coverage on real logs or proof that an export is permitted.
planted items = 2 + 2 + 2 + 2 = 8
credential share = 2 / 8 = 25%
bearer share = 2 / 8 = 25%
email share = 2 / 8 = 25%
host share = 2 / 8 = 25%
sum = 25 + 25 + 25 + 25 = 100%
expected fixture matches = 8 / 8 = 100%, plus 1 clean line with 0 replacements
real-log recall and disclosure risk are not measured by these fixturesThe count does not establish successful redaction. Inspect every known item and the remaining content: matches can miss, overlap, or affect clean text. Extend the fixtures and patterns as appropriate, then separately confirm sharing permission.
It catches false replacements on that one fixture. It does not prove that other clean text is preserved or that all sensitive content is removed.