Skip to content
1Claw Academy
Curriculum/Integrations & Ecosystem2 minIntermediate · Lesson 3 of 11

Lab: print a secret without meaning to

Lab

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. 1

    Log a response object the way you would while working out why a call failed.

    bash
    cat > /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. 2

    One line of debugging output, one credential in your log aggregator.

    text
    fetched secret: {'data': {'path': 'stripe/key', 'type': 'api_key', 'value': 'sk-live-9f2a'}, 'error': None, 'meta': {'status': 200}}
    fetched secret: stripe/key
  3. 3

    Clean up.

    bash
    rm /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.
Tip

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.

Watch out

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 questions
1

What made this leak so easy?

2

Why does structured logging not solve it?

3

What is the durable fix?