Sanitize stack
Skill 0xZOne/sanitize-stack
A worked example of building a Claude Code skill from scratch: decisions, design, smoke test, maintenance.
npx -y skills add 0xZOne/sanitize-stackAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
This skill should be used when the user asks to "sanitize a crash stack", "scrub a stack trace", "clean up a stack for crbug", "prepare a stack for issues.chromium.org", "prepare a stack for Gerrit", "脱敏崩溃堆栈", or pastes a native crash stack (typically Chromium or a Chromium-based embedder) and expresses intent to attach it to a public issue tracker or code review. Transforms raw symbolicated stacks into paste-ready comments by scrubbing downstream module names, normalizing locale tokens, collapsing verbose C++ template signatures, eliding Chromium boilerplate frames, and flagging residual PII for human review.
SKILL.md
10.9 KB, as published. Nobody here has run it
Sanitize Crash Stack
Transform a raw symbolicated native crash stack into a paste-ready comment for issues.chromium.org, crbug.com, or a Chromium Gerrit CL description. Public trackers require module names and debug output to be free of downstream product identifiers and environment PII; enforce a consistent sanitization and trimming pipeline so every posted stack has the same shape and safety guarantees.
When This Skill Applies
Trigger on a pasted crash stack combined with any of:
- Intent to file or comment on a public bug (
crbug.com,issues.chromium.org,bugs.chromium.org) - Intent to attach to a Gerrit CL description or review comment
- Explicit phrases like "sanitize", "scrub", "脱敏", "clean up before posting"
Skip this skill when:
- The target is a private/internal tracker and the user explicitly wants the raw stack preserved
- The stack is not symbolicated (raw addresses + pdb only) — ask the user to symbolicate first using
windbg/minidump_stackwalk/llvm-symbolizer - The stack is already in Chromium-standard form with no downstream identifiers — in that case offer trim-only mode (Steps 4-6) and skip scrub steps
Input Handling
Locate the stack trace via:
- If invoked with a file path argument, read the file with the Read tool
- Otherwise, scan the most recent user messages for a block of lines matching native stack trace patterns (function names with
!, line numbers, source file references) - If no stack is found, ask the user to paste one
Do not proceed without an explicit stack. Do not fabricate or reconstruct missing frames.
Pipeline
Execute the six steps in order. Record each transformation to produce the final diff summary.
Step 1: Scrub Downstream Module Names
Regex-scan for module name patterns: ^\s*(\w+)\.(dll|exe|so|dylib)!.
Collect every unique module name observed. Classify each as:
- Chromium-standard:
chrome,chrome_elf,content_shell,chromedriver,libchrome, or any module prefixed withtest_ - Downstream / unknown: anything else (examples:
brave,vivaldi,opera,msedge, custom embedder names)
Replacement rules:
- Chromium-standard → preserve as-is; record "Symbols from upstream Chromium build" for the provenance line
- Downstream → replace every occurrence with
chrome.dll(or matching extension:.exe→chrome.exe,.so→libchrome.so,.dylib→libchrome.dylib); record "Module names normalized to chrome.* (symbolicated against upstream source)" for the provenance line
If multiple distinct downstream modules appear, treat as a warning and list all observed names under Safety Review for human confirmation — this may indicate a mixed-process or mis-symbolicated stack.
Step 2: Normalize Locale Tokens
Apply these substitutions before rendering:
| Source | Replacement |
|---|---|
行 (CJK line marker, MSVC/WinDbg CN/JP locale) | line |
Zeile (German) | line |
ligne (French) | line |
строка (Russian) | line |
| Any other non-ASCII locale token | Flag in Safety Review and preserve |
Debugger locale pollution is common on Windows; MSVC and WinDbg emit localized line markers depending on the developer's OS language.
Step 3: Collapse C++ Template Signatures
Apply the substitution table, in order. Earlier rules must run before later ones because later rules assume earlier cleanup already happened.
| Pattern | Replacement |
|---|---|
std::__Cr::basic_string<char16_t, std::__Cr::char_traits<char16_t>, std::__Cr::allocator<char16_t>> | std::u16string |
std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>> | std::string |
std::__Cr::unique_ptr<T, std::__Cr::default_delete<T>> | std::unique_ptr<T> |
std::__Cr:: prefix anywhere | (delete) |
base::internal::Invoker<...huge variadic...>::RunImpl<...> | Elide frame entirely — boilerplate |
base::internal::DecayedFunctorTraits<...>::Invoke<...> | Elide frame entirely — boilerplate |
Preserve these types verbatim: scoped_refptr<T>, base::WeakPtr<T>, base::OnceCallback<Sig>, base::RepeatingCallback<Sig>, raw_ptr<T>, raw_ref<T>.
Step 4: Classify Signal vs Noise Frames
Keep as signal:
- Any frame with a source path under
chrome/,components/,content/,blink/,third_party/blink/,ui/,net/,gpu/,services/,sandbox/ - Any frame whose function name matches a class or method mentioned in the current bug context
- The
*::AcceptSyncMessageframe fromIPC::ChannelAssociatedGroupController— always keep; this is the decisive marker for sync IPC race diagnosis - At least one
mojo::InterfaceEndpointClient::HandleValidatedMessageframe for mojo dispatch context - Generated mojo
*::StubDispatch::AcceptWithResponderframes
Elide as noise, replacing the contiguous tail at the bottom of the stack with a single summary line.
For the authoritative list of noise-frame families and patterns, consult:
references/noise-frames.md— Complete Chromium boilerplate frame classification with regex patterns
The most commonly elided families:
base::internal::*(Bind/Invoke machinery)base::TaskAnnotator::*base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::*base::MessagePump*::*,base::RunLoop::*content::BrowserMainLoop::*,content::BrowserMain*,content::ContentMain*ChromeMain,MainDllLoader::*,wWinMain,main,WinMain- Mojo dispatch middle frames:
MessageDispatcher::Accept,HandleIncomingMessage,HandleIncomingMessageThunk::Accept - Sibling mojo stub wrappers:
*::Stub<RawPtrImplRefTraits>::AcceptWithResponder(keep onlyStubDispatchvariant)
Replace the elided tail with one line matching the actual boilerplate family:
[base::Bind / TaskAnnotator / MessagePumpForUI / BrowserMain — standard UI-thread dispatch, elided]
Adjust the summary if the crash is on a worker thread (mention ThreadPoolImpl::Worker instead), or on an IO thread (MessagePumpLibevent or similar).
Step 5: Render Markdown Output
Format the sanitized stack as:
-
Provenance paragraph (outside the code block). Adjust to reflect only the transformations that were actually performed:
Adding the browser-side crash stack for context. Symbolicated against upstream source; module names normalized to
chrome.*, C++ template signatures shortened, standard UI-thread dispatch tail elided. Line numbers are from a symbolicated downstream build and may differ by a few from upstream HEAD. -
Fenced code block containing the sanitized frames. Each frame occupies two lines:
- Line 1:
module.dll!<function signature>(collapsed per Step 3) - Line 2, indented 4 spaces:
source_file.cc:line_number
- Line 1:
-
Elision marker as the last line inside the code block.
-
Optional
### Why this stack matterssection if any of these conditions hold:- An
AcceptSyncMessageframe is present — explain the sync IPC race window in one paragraph - The crash is inside a bound callback invoked from
TaskAnnotator— note that the failing work was posted from elsewhere, so the poster site is not directly visible - The stack spans a known Chromium trap (re-entrancy into a destroyed object, UAF during shutdown, etc.)
- An
Step 6: Safety Review
Scan the sanitized stack for residual risk patterns before presenting it:
| Pattern | Action |
|---|---|
/Users/[^/]+/, C:\\Users\\[^\\]+\\, /home/[^/]+/ | Flag the username — likely a symbol path leak |
\S+@\S+\.\S+ (email literal) | Flag |
\b[a-z0-9-]+\.(corp|internal|local|intranet)\b | Flag internal hostname |
| IPv4 / IPv6 literals | Flag |
| Non-ASCII characters (any remaining after Step 2) | Flag — suspicious |
| Original downstream module names (missed in Step 1) | Flag — indicates regression in Step 1 matcher |
Do not auto-delete flagged items — list them under a ### Safety review section for human judgment. A CamelCase class name that looks like a codename may actually be a legitimate Chromium class (example: JavaScriptTabModalDialogManagerDelegateDesktop). Defer that call to the human.
Output Format
Present the final result to the user in this order:
- One-line summary of transformations performed. Example: "Scrubbed 1 downstream module (
downstream→chrome), elided 18 boilerplate frames, collapsed 4 template signatures, flagged 0 residual PII." - Provenance paragraph matching actual transformations.
- Fenced code block with the sanitized stack.
- Optional
### Why this stack mattersdiagnostic observations. ### Safety reviewlist (even if empty — print "No residual concerns detected.").- Paste instructions — one sentence reminding the user this content is not auto-posted; manual copy into the tracker or Gerrit comment field is required, and the Preview button should be used before Submit.
Validation Checklist
Before returning the output, verify:
- Provenance paragraph matches only the transformations actually performed
- No downstream module names remain (if Step 1 scrub was applied)
- All non-ASCII characters accounted for (normalized in Step 2 or flagged in Step 6)
- Elision line accurately reflects the noise family elided (UI thread vs worker vs IO)
- Safety review section is present (empty-state message if no flags)
- At least the top signal frame (the crashing function) is preserved with original function name
- Line numbers are not modified — only module names and template signatures are transformed
Additional Resources
Reference Files
references/noise-frames.md— Authoritative list of Chromium frame families classified as noise, with regex patterns and worker-thread variants
Common Mistakes to Avoid
- Do not guess line numbers against upstream HEAD. Line numbers may differ between downstream builds and upstream; preserve the original numbers and note the possible drift in the provenance paragraph.
- Do not strip
AcceptSyncMessage. It is the decisive marker that distinguishes a sync IPC race from an async dispatch race. Reviewers use it to diagnose the race window. - Do not auto-resolve CamelCase flags. Class names that look like product codenames may be legitimate Chromium types. Only a human can decide.
- Do not post the output directly. This skill prepares a paste-ready block; the user must manually paste and preview in the tracker.