Skip to content

appmap sanitize leaves array-valued header values (set-cookie) untokenized #2404

Description

@devin-ai-integration

AppMap CLI 3.203.0 (appmap --version), source at packages/cli/src/lib/sanitizeAppMap.ts.

What happens

sanitizeHeaders masks a header only when its value is a string:

function sanitizeHeaders(headers: Record<string, unknown> | undefined, masker: ValueMasker): void {
  if (!headers) return;
  for (const name of Object.keys(headers)) {
    const value = headers[name];
    if (typeof value === 'string') headers[name] = masker.mask(value);
  }
}

Rack (the Ruby agent) records multi-valued response headers, set-cookie above all, as an array
of strings. Those are skipped, so the session cookie the sanitizer exists to remove stays in the
file, while the request's Cookie header (a string) is tokenized.

Repro

Minimal AppMap (two events):

{"version":"1.12","metadata":{"name":"repro"},"classMap":[],"events":[ {"id":1,"event":"call","thread_id":1,"http_server_request":{"request_method":"GET","path_info":"/x","headers":{"Cookie":"_gumroad_app_session_test=SECRETCOOKIE"}}}, {"id":2,"event":"return","thread_id":1,"parent_id":1,"http_server_response":{"status":200,"headers":{"etag":"W/\"abc\"","set-cookie":["_gumroad_guid=1de65c26-uuid; path=/","_gumroad_app_session_test=SECRETCOOKIE; httponly"]}}}]}

in.appmap.json in this folder, two events, one request and its response.

cp in.appmap.json out.appmap.json
appmap sanitize out.appmap.json

Output: 2 distinct value(s) tokenized. Result:

request  headers: {"Cookie": "<v1>"}
response headers: {"etag": "<v2>",
                   "set-cookie": ["_gumroad_guid=1de65c26-uuid; path=/",
                                  "_gumroad_app_session_test=SECRETCOOKIE; httponly"]}

Expected: every element of the array tokenized, e.g. ["<v3>", "<v4>"] (or, keeping the cookie
name as schema, ["_gumroad_guid=<v3>", "_gumroad_app_session_test=<v4>"]).

Seen in the wild

Gumroad request-spec recordings: every response that sets a session carries the encrypted
_gumroad_app_session_test cookie in set-cookie, untouched after appmap sanitize. Found while
packaging evlawler/goldtrace-examples PR 53; the same values are in the baselines of PR 51.

Suggested fix

if (typeof value === 'string') headers[name] = masker.mask(value);
else if (Array.isArray(value))
  headers[name] = value.map((v) => (typeof v === 'string' ? masker.mask(v) : v));

Found while sanitizing Gumroad request-spec recordings for a gold-trace review corpus.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions