Skip to content

Memory Dump Attack on Encrypted Plugin System - Seeking Solution #169

@lovestaco

Description

@lovestaco

Problem Description

I have a system that stores sensitive AI prompts securely, but they're still extractable via memory dumps despite encryption and memguard protection.

Current Workflow

  1. Source: Sensitive prompts stored in prompt.go file:

    package main
    
    func GetData() string {
        return `# Role and Context
    You are an expert OpenAPI 3.0.0 specification generator with deep
    # Guidelines
    ## General Formatting
    ## Endpoint Specifications
    ...` // Large sensitive prompt content
    }
  2. Build Process:

    • prompt.go is compiled into prompt.so shared library
    • prompt.so is encrypted using AES-256-GCM → prompt.so.enc
  3. Runtime Process:

    // Decrypt prompt.so.enc → prompt.so (temporary file)
    decryptFile("prompt.so.enc", tempPath)
    
    // Load plugin
    plugin.Open(tempPath)
    
    // Extract data and protect with memguard
    rawData := getDataFunc() // Gets the prompt string
    protected := memguard.NewBufferFromBytes([]byte(rawData))
  4. Usage: Need to process prompt data (count characters, analyze content) but NOT expose it via API

Security Issue

Memory dumps still extract the original prompts despite memguard protection:

# Memory extraction shows:
[ERROR] FOUND in memory: 'Role and Context'
[ERROR] FOUND in memory: 'OpenAPI'  
[ERROR] FOUND in memory: 'Guidelines'
# Full prompt content recoverable from process memory

Root Cause Analysis

The memory leak occurs because:

  1. Plugin Loading: plugin.Open() loads the compiled prompt.so into memory, including all string literals from the original prompt.go
  2. String Constants: The GetData() function's return value exists as embedded string constants in the plugin's data section
  3. Memory Segments: These constants are loaded into regular process memory where memory dumps can extract them
  4. Memguard Limitation: memguard protects the copy, but original plugin data remains in unprotected memory

Current Architecture

prompt.go (source) 
    ↓ [compile]
prompt.so (shared library with embedded strings)
    ↓ [encrypt] 
prompt.so.enc (encrypted file)
    ↓ [runtime decrypt]
prompt.so (temporary, loaded by plugin.Open)
    ↓ [extract + memguard]
Protected memory (but original still extractable)

Security Requirement

  • Can process data: Count characters, analyze prompt content
  • Cannot extract via memory dump: Original prompt should not be recoverable from process memory
  • Encrypted at rest: Data stored securely in prompt.so.enc
  • Dynamic loading: System loads/decrypts at runtime, not compile-time

Questions for the Community

  1. Is this approach fundamentally flawed? Can we ever prevent memory extraction when loading compiled Go plugins with embedded strings?

  2. Alternative plugin architectures:

    • Should prompt.go read from an encrypted file instead of having embedded strings?
    • Could we use code generation to obfuscate the strings?
    • Is there a way to store strings in a format that's not directly extractable?
  3. Non-plugin alternatives:

    • Custom encrypted file format with streaming decryption?
    • In-memory XOR encoding/decoding?
    • External process for prompt handling?
  4. Memory protection: Are there Go libraries that provide stronger memory protection than memguard against dump attacks?

Environment

  • Go version: go1.24.4
  • OS: Linux
  • Libraries: memguard, standard library plugins
  • Attack vector: Memory dump tools scanning process memory regions

Expected Outcome

A solution where we can:

  • Store prompts securely (currently in prompt.go → compiled → encrypted)
  • Process prompt data at runtime (count chars, analyze, etc.)
  • Prevent memory dump attacks from extracting the original prompt content
  • Maintain reasonable development workflow

Any suggestions on secure plugin architectures or alternative approaches would be greatly appreciated!

Repo link: https://github.com/lovestaco/simple-plugin-memguard

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions