C.W.K.
Stream
Lesson 04 of 04 · published

Log the Fingerprint, Not the Words

~9 min · privacy, logging, secrets

Level 0Silent
0 XP0/36 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"Ordinary requests log hashes and lengths, not the private text. The one exception — Studio text — is authored on purpose."

Debuggable Without Being Nosy

An engine that speaks private words has to be careful what it writes down. Bellows logs enough to identify and debug a request — a hash of the text, its length, the model, the language — but never the full private text itself. You can answer "which request was this, and did it change?" from a fingerprint. You don't need the actual words in a log file to do it, and once they're in a log file, they leak wherever logs go.

The Named Exception

There's exactly one place Bellows records text as content: Studio. Studio text is explicit, authored project data — you wrote it into a project on purpose, the way you'd type into a document. Recording it is the point, not a privacy hole. The discipline isn't "never store text," it's "private text is a fingerprint by default, and the exception is named and deliberate."

Keys Live Even Further Down

Provider API keys get the strictest rule of all: they never enter source, SQLite, a plist, a UI response, or a log line — anywhere. A key is read from the environment at the edge and used; it is never persisted into the engine's own state or echoed back in an error. The general shape is a gradient of secrecy: keys never anywhere, private text as a fingerprint, and only deliberately-authored content stored in full.

Code

A fingerprint is enough to debug; the words are not needed·python
import hashlib, logging
log = logging.getLogger("bellows")

def log_request(text: str, settings: Settings) -> None:
    # Ordinary text is PRIVATE. Log a fingerprint, never the words.
    log.info(
        "synth request text=sha256:%s len=%d model=%s lang=%s",
        hashlib.sha256(text.encode()).hexdigest()[:12],
        len(text),
        settings.model,
        settings.language,
    )
    # NEVER written to source, SQLite, plist, UI response, or logs:
    #   - provider API keys (read from env at the edge, used, never persisted)
    #   - full private text
    # Studio text is the ONE exception: explicit, authored project data.

External links

Exercise

Open the logs of something you've built and read them as an attacker would. Find one line that logs private content or a secret — a full request body, a token, an email, a filename that reveals something. Rewrite it to log a fingerprint (hash plus length plus a few safe fields) that still lets you debug, and name the one kind of data you'd deliberately store in full and why.
Hint
For each field ask: 'do I need the value, or just to tell two values apart and notice a change?' If the latter, a hash does the job and can't leak. Only deliberately-authored content earns full storage.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.