Skip to content

[Export Audit] Dead export escapeShellArg in security-critical shell-utils module #4068

@github-actions

Description

@github-actions

API Surface Issue

Category

Unused export / Dead export in security-critical module

Summary

  • File: src/parsers/shell-utils.ts
  • Symbol: escapeShellArg
  • Issue: escapeShellArg is exported as part of the public API of shell-utils.ts but is never imported in any production code — only in test files. The companion export joinShellArgs (which internally calls escapeShellArg) is used in production and re-exported via option-parsers.ts.

Evidence

$ grep -rw "import.*escapeShellArg" src/ --include="*.ts"
src/option-parsers-env.test.ts:import { escapeShellArg } from './parsers/shell-utils';
src/parsers/shell-utils.test.ts:import { escapeShellArg, joinShellArgs } from './shell-utils';

Production usage check (no results outside tests):

$ grep -rw "escapeShellArg" src/ --include="*.ts" | grep -v ".test.ts"
src/parsers/shell-utils.ts:export function escapeShellArg(arg: string): string {
src/parsers/shell-utils.ts:  return args.map(escapeShellArg).join(' ');

option-parsers.ts only re-exports joinShellArgs, not escapeShellArg:

$ grep -n "escapeShellArg\|joinShellArgs" src/option-parsers.ts
18:  joinShellArgs,

Recommended Fix

  1. Remove the export keyword from escapeShellArg in src/parsers/shell-utils.ts — it is an internal implementation detail of joinShellArgs and does not need to be part of the public API
  2. Update test imports: src/option-parsers-env.test.ts should test joinShellArgs directly instead of escapeShellArg, or the test can be kept as a white-box test by moving it to shell-utils.test.ts

Impact

  • Dead code risk: Medium (the exported surface of a security-critical function — shell argument escaping — is misleadingly wider than necessary, potentially encouraging direct use that bypasses joinShellArgs)
  • Maintenance burden: Low (single symbol, small surface area)

Detected by Export Audit workflow. Triggered by push to main on 2026-05-30

Generated by API Surface & Export Audit · sonnet46 2.3M ·

  • expires on Jun 29, 2026, 3:45 PM UTC

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions