Lab: print a secret without meaning to
Log an SDK response the way everyone does during debugging, and read the value back out of your own log.
Every SDK in this track returns an envelope with the value inside it. That shape is convenient and it makes one debugging habit unusually expensive.
- 1
Log a response object the way you would while working out why a call failed.
bashcat > /tmp/logresp.py <<'EOF' import logging logging.basicConfig(format="%(message)s", level=logging.INFO) resp = {"data": {"path": "stripe/key", "type": "api_key", "value": "sk-live-9f2a"}, "error": None, "meta": {"status": 200}} logging.info("fetched secret: %s", resp) # the habit logging.info("fetched secret: %s", resp["data"]["path"]) # the fix EOF python3 /tmp/logresp.py - 2
One line of debugging output, one credential in your log aggregator.
textfetched secret: {'data': {'path': 'stripe/key', 'type': 'api_key', 'value': 'sk-live-9f2a'}, 'error': None, 'meta': {'status': 200}} fetched secret: stripe/key - 3
Clean up.
bashrm /tmp/logresp.py
Nothing unusual happened. Somebody logged an object to find out what was in it, which is the correct instinct, and the object happened to contain a credential.
- Log the field you need, never the container. path, type and status answer almost every debugging question; value answers none of them.
- The same applies to exception handlers that attach request or response context, which is how a value reaches an error tracker without any log line naming it.
- Structured logging does not help here. It serialises the object faithfully, which is exactly the problem.
Grep your codebase for logging calls that pass a whole response, a whole config, or a whole request object. It is a five-minute search and it is where secrets in log aggregators come from.
This is also the argument for Execution Intents in one sentence: a value your code never receives is a value your code cannot accidentally log.
Check your understanding
3 questionsWhat made this leak so easy?
Why does structured logging not solve it?
What is the durable fix?