tlumi is pre-1.0. Security fixes are made against main and shipped in the next release. There is no LTS branch.
Please do not file a public GitHub issue for security-sensitive reports. Instead, use GitHub private vulnerability reporting: open the repository's Security tab and click Report a vulnerability. If you cannot use GitHub, email the maintainer at git.jaydoubleu@gmail.com. Include:
- A description of the vulnerability
- A reproduction (minimal
tlumi.yaml+infra.py+ command sequence) - Your assessment of impact
- Any suggested remediation
If you do not receive an acknowledgement within 7 days, please follow up. Coordinated disclosure is welcome; we will agree on a disclosure timeline once the issue is confirmed.
tlumi runs locally and operates on resources you have credentials for. The trust boundary is your local machine. Specifically:
infra.pyis executed Python. Only runtlumi plan/apply/destroy/refresh/importin directories you trust. The entry file is loaded viaimportlib.util.spec_from_file_locationagainst an exact path (nosys.pathsearch), but it still executes as Python with your privileges.- State files contain plaintext secrets unless you opt into encryption. Set
TLUMI_SECRETS_PASSPHRASEto enable encryption; otherwise tlumi refuses to proceed unlesssecrets.allow_unencrypted: trueis set intlumi.yaml. The.tlumi/directory is created with0700permissions to limit local exposure. - Auto-installed binaries. tlumi downloads the Pulumi CLI (via
PulumiCommand.install(), trust delegated to the Pulumi SDK) into~/.tlumi/cache/pulumi/<sdk_version>/, falling back to the per-project.tlumi/cache/pulumi_home/; apulumibinary onPATHis never used. uv is resolved fromPATHfirst; if absent, tlumi downloads it from GitHub releases (verified against a SHA-256 checksum) into~/.tlumi/cache/uv/. In restricted environments, pre-install uv onPATHand pre-seed the Pulumi CLI at~/.tlumi/cache/pulumi/<sdk_version>/bin/pulumi(matching the installed Pulumi SDK version) to avoid both downloads. - Remote backend URL credentials. tlumi masks passwords, bare-username tokens, and sensitive query parameters before echoing backend URLs to the terminal. Real credentials still travel to the backend; the masking only protects the display path.
- State backups. State mutations create timestamped backups under
.tlumi/backups/with0600perms viaO_CREAT|O_EXCL. Symlink checks precede every mkdir and file write on user-controlled paths. - SDK monkey-patch.
sdk_compat.pypatches private Pulumi SDK functions to suppress local filesystem paths from persisting in state. This is documented in DESIGN.md ADR-006. The patch fails open with a warning if the SDK layout changes.
- Vulnerabilities in dependencies (Pulumi SDK, uv, Rich, Typer) should be reported to those projects. tlumi will track upstream advisories and bump.
- Issues that require physical access to the machine running tlumi.
- Social engineering of users into running malicious
infra.pyfiles (the trust model assumes the user trusts the project directory).
- Never commit
.tlumi/state/to a public repository. The auto-generated.gitignoreexcludes it; verify before pushing. - Use a remote backend with locking (S3, Azure Blob) for team and CI use. The local file backend has no distributed locking.
- Set
TLUMI_SECRETS_PASSPHRASEfor any project that uses Pulumi secret values, even in development. - Project variables are NOT secrets. Values from
--var,--var-file,TLUMI_VAR_*, andtlumi.yamlare written as plaintext Pulumi config (stored unencrypted in.tlumi/Pulumi.<stack>.yaml, visible in thepulumi config setprocess arguments) regardless ofTLUMI_SECRETS_PASSPHRASE. Do not put real secrets in any variable channel. For values that must be encrypted at rest, create them as Pulumi secrets insideinfra.py(e.g.config.require_secret(...)orpulumi.Output.secret(...)); those are encrypted with the passphrase. Among the variable channels, prefer--var-file(gitignored) orTLUMI_VAR_*over--var KEY=VALUE, which additionally lands in shell history.