Skip to content

[WIP] Implement botlockbox as a secure credential-injecting proxy#1

Merged
trodemaster merged 1 commit intomainfrom
copilot/implement-botlockbox-tool
Feb 18, 2026
Merged

[WIP] Implement botlockbox as a secure credential-injecting proxy#1
trodemaster merged 1 commit intomainfrom
copilot/implement-botlockbox-tool

Conversation

Copy link

Copilot AI commented Feb 18, 2026

Implementation Plan for botlockbox

  • Initialize Go module with dependencies
  • Create main.go entry point
  • Implement cmd/ package (root.go, seal.go, serve.go)
  • Implement internal/config package (config.go, loader.go)
  • Implement internal/secrets package (envelope.go, seal.go, unseal.go, helpers.go, memlock.go)
  • Implement internal/proxy package (proxy.go, ephemeral_ca.go, injector.go, response_scrubber.go, upstream_verify.go, audit.go)
  • Implement internal/matcher package (matcher.go)
  • Create example botlockbox.yaml config file
  • Create comprehensive README.md
  • Create Makefile
  • Build and test the complete implementation
  • Run security checks (codeql, code review)
Original prompt

Overview

Implement botlockbox — a Go command-line tool that acts as a credential-injecting HTTPS/HTTP MITM proxy for AI agents, MCP servers, and CLI tools. The proxy injects API credentials into outbound requests transparently, so callers (including AI agents with root shell access) never see the credentials.

Security Goals

  1. Zero plaintext secrets on disk — secrets are encrypted with filippo.io/age at seal time and only decrypted in memory at runtime
  2. Cryptographically bound host allowlists — at seal time the allowed hosts for each secret are committed inside the encrypted envelope; modifying the config file to add new hosts is detected and blocked at startup
  3. Memory hardening — process sets PR_SET_DUMPABLE=0, disables core dumps, calls mlockall, uses MADV_DONTDUMP on secret pages, and stores secrets in memguard encrypted enclaves
  4. Ephemeral MITM CA — the ECDSA CA used for MITM is generated in memory at startup and never written to disk
  5. Per-injection host check — every credential injection is validated against the sealed allowlist (not just at startup)
  6. Upstream TLS verification — the proxy always verifies upstream TLS certs to defeat DNS rebinding attacks
  7. Response scrubbing — known credential patterns are redacted from API responses before forwarding to the agent
  8. Audit logging — every injection is logged (secret name only, never value)

Repository Structure

Create the following files:

botlockbox/
├── main.go
├── go.mod
├── go.sum
├── botlockbox.yaml          # example config (no secrets)
├── README.md
├── cmd/
│   ├── root.go
│   ├── seal.go
│   └── serve.go
└── internal/
    ├── config/
    │   ├── config.go
    │   └── loader.go
    ├── secrets/
    │   ├── envelope.go
    │   ├── seal.go
    │   ├── unseal.go
    │   ├── helpers.go
    │   └── memlock.go
    ├── proxy/
    │   ├── proxy.go
    │   ├── ephemeral_ca.go
    │   ├── injector.go
    │   ├── response_scrubber.go
    │   ├── upstream_verify.go
    │   └── audit.go
    └── matcher/
        └── matcher.go

Detailed File Specifications

go.mod

Module: github.com/trodemaster/botlockbox

Dependencies:

  • filippo.io/age v1.2.0 — age encryption
  • github.com/elazarl/goproxy latest — HTTP/HTTPS proxy
  • github.com/spf13/cobra v1.8.1 — CLI
  • gopkg.in/yaml.v3 v3.0.1 — YAML config and secrets
  • golang.org/x/term — passphrase prompt
  • golang.org/x/sys — unix syscalls for memlock
  • github.com/awnumar/memguard — encrypted in-memory secret storage

main.go

Simple entrypoint calling cmd.Execute().

cmd/root.go

  • Cobra root command named botlockbox
  • Persistent flag --config defaulting to botlockbox.yaml
  • loadConfig(path string) (*config.Config, error) helper

cmd/seal.go

Subcommand seal:

  • Reads plaintext secrets YAML from stdin
  • Loads config to derive AllowedHostsFromRules()
  • Prints the host bindings being committed
  • Calls secrets.Seal()
  • After sealing, calls os.Chmod(cfgFile, 0444) to make config read-only
  • Flags: --identity (path to age private key file), --passphrase (bool, use passphrase instead)

cmd/serve.go

Subcommand serve:

  1. Calls secrets.HardenProcess() FIRST before anything else
  2. Loads config
  3. Calls secrets.Unseal() to decrypt envelope into memory
  4. Calls envelope.Validate(configAllowedHosts) — hard os.Exit(1) on mismatch with clear security violation message
  5. Prints sealed-at timestamp and verified host bindings
  6. Calls proxy.New(cfg, envelope)
  7. Starts http.ListenAndServe
  • Flags: --identity, --passphrase

internal/config/config.go

type Config struct {
    Listen       string `yaml:"listen"`        // default "127.0.0.1:8080"
    SecretsFile  string `yaml:"secrets_file"`  // path to .age file
    Verbose      bool   `yaml:"verbose"`
    IdentityFile string `yaml:"identity_file"`
    Rules        []Rule `yaml:"rules"`
}

type Rule struct {
    Name   string `yaml:"name"`
    Match  Match  `yaml:"match"`
    Inject Inject `yaml:"inject"`
}

type Match struct {
    Hosts        []string `yaml:"hosts"`
    PathPrefixes []string `yaml:"path_prefixes,omitempty"`
}

type Inject struct {
    Headers     map[string]string `yaml:"headers,omitempty"`
    QueryParams map[string]string `yaml:"query_params,omitempty"`
}

AllowedHostsFromRules() method on *Config:

  • Walks every rule's inject headers and query params
  • Extracts secret names from {{secrets.NAME}} template syntax using regex \{\{secrets\.(\w+)\}\}
  • Returns map[string][]string mapping secretName → deduplicated list of hosts from that rule's match

internal/config/loader.go

Load(path string) (*Config, error) — reads YAML file, sets defaults (Listen = "127.0.0.1:8080", SecretsFile = "~/.botlockbox/secrets.age"), expands ~ in paths.

internal/secrets/envelope.go

type SealedEnvelope struct {
    Version      int                 `json:"version"`
    ...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

*This pull request was created from Copilot chat.*
>

<!-- START COPILOT CODING AGENT TIPS -->
---

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more [Copilot coding agent tips](https://gh.io/copilot-coding-agent-tips) in the docs.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot wasn't able to review any files in this pull request.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@trodemaster trodemaster marked this pull request as ready for review February 18, 2026 16:26
@trodemaster trodemaster merged commit 89dcb3d into main Feb 18, 2026
1 check failed
Copilot AI requested a review from trodemaster February 18, 2026 16:26
Copilot stopped work on behalf of trodemaster due to an error February 18, 2026 16:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants