Security

fleche provides a built-in cryptographic security layer for filesystem-based storage backends (pickle, cloudpickle, and dill) to protect against insecure deserialization vulnerabilities. This prevents arbitrary code execution if an attacker manages to tamper with or replace the cache files.

Enabling Security

By default, if no secret key is configured, security is turned off and caches are read and written as plain serialized files.

Security can be enabled in two ways:

Via environment variable (recommended — keeps secrets out of config files):

export FLECHE_SECRET_KEY="$(python -c 'import secrets; print(secrets.token_hex(32))')"

The value must be a colon-separated list of hex-encoded byte strings ([0-9a-f]+). fleche decodes each segment to raw bytes before use.

Via config file (fleche.toml):

[mycache]
values.type = "cloudpickle"
values.root = "~/.fleche/values"
values.secret_key = ["<hex-encoded-key>"]

The secret_key value is a list of hex-encoded strings using the same format as FLECHE_SECRET_KEY.

Warning

Storing secrets in config files risks accidentally committing them to version control. Prefer the environment variable approach for sensitive deployments.

Both sources use the same key format and normalization logic: any bytes value is used as-is, and any str value is interpreted as a hex-encoded byte string. HMAC-SHA256 imposes no minimum key length, though using at least 32 random bytes (256 bits) is strongly recommended.

When enabled, fleche will compute an HMAC-SHA256 signature for all newly cached data and append it to the file as a 64-byte hex string. Upon loading, fleche separates the signature and verifies the integrity of the data. If the signature is invalid or missing entirely from a modified file, a KeyError is raised, effectively treating the entry as a cache miss.

Backward Compatibility

The signing implementation is designed to be partially backward compatible. Signatures are appended to the end of the pickle byte stream.

  1. Unsigned to Signed: Once security is enabled with a secret key, all cache entries must be signed. Existing completely unsigned cache files will fail validation and be treated as misses, requiring caches to be rebuilt securely.

  2. Signed to Unsigned: If you disable the secret key, or a different unauthenticating instance reads the cache, the standard pickle library will successfully load the data and naturally ignore the trailing 64-byte signature.

Key Rotation and Distributed Trust

You can specify multiple hex-encoded keys separated by colons, in both the environment variable and the config file:

export FLECHE_SECRET_KEY="aabbccdd01:eeff009988:1122334455"

Or in fleche.toml:

values.secret_key = ["aabbccdd01", "eeff009988", "1122334455"]

When multiple keys are provided: * Writing: The first key in the list (aabbccdd01) is always used to sign new cache entries. * Reading: fleche will iterate through all keys in the list. If the cache file’s signature matches any of the configured keys, the data is accepted.

This allows you to seamlessly rotate compromised or old keys without invalidating your existing cache, and it allows you to load and trust data generated by other known fleche installations.