Security

Dyngle is designed for workflow automation, but understanding its security characteristics is important for safe usage.

Command Execution Model

No Shell Interpretation

Commands are executed directly using Python's subprocess.run() with arguments parsed in a shell-like fashion:

Safe:

  • Arguments are passed as separate parameters to the subprocess
  • No shell meta-characters are interpreted (|, >, &&, ;, etc.)
  • Environment variables are not automatically expanded

This reduces common shell injection risks:

dyngle:
  operations:
    safe-example:
      - echo "User input: {{user-input}}"
      - curl "{{url}}"

Even if user-input contains shell meta-characters, they won't be interpreted as shell commands.

Template Substitution

Templates are evaluated before commands are executed:

dyngle:
  operations:
    example:
      - echo "Hello {{name}}"

Security implications:

  • Template values are substituted as strings
  • Values from untrusted sources could still inject command arguments
  • Validate and sanitize external inputs before use

Configuration Security

Not Robust to Malicious Configuration

Important: Dyngle is not designed to be robust against malicious configuration files.

  • Configuration files contain Python expressions that are evaluated
  • Expressions have access to system capabilities (file operations, networking, etc.)
  • Only use configuration files from trusted sources

Never run Dyngle with untrusted configuration files.

Configuration File Permissions

Protect your configuration files:

# Set appropriate permissions
chmod 600 ~/.dyngle.yml
chmod 600 .dyngle.yml

This is especially important if your configuration contains:

  • Credentials or API keys
  • Sensitive operation logic
  • Private operations that manage secrets

Expression Evaluation

Python Execution Context

Expressions are evaluated in a restricted Python context:

Available:

  • Read-only operations (mostly)
  • Standard library modules (datetime, math, etc.)
  • Limited file system access via Path() (current directory only)

Security notes:

  • Expressions can still perform many operations
  • The restriction is not a security sandbox
  • Malicious expressions could cause harm

Path() Restrictions

The Path() function in expressions is restricted to the current working directory:

dyngle:
  expressions:
    config: "Path('.dyngle.yml')"  # OK
    # bad: "Path('/etc/passwd')"  # Error

This prevents expressions from accessing arbitrary filesystem locations.

MCP Server Security

Tool Exposure

When running as an MCP server, operations become accessible to AI assistants:

Public operations:

  • Exposed as tools
  • Can be called by AI assistants
  • May be called with unexpected inputs

Private operations:

  • Not exposed via MCP
  • Cannot be called by AI assistants
  • Useful for sensitive operations

Best Practices for MCP

  1. Use access control:
dyngle:
  operations:
    get-secret:
      access: private  # Not exposed
      return: secret
      steps:
        - aws secretsmanager get-secret-value --secret-id api-key => secret
    
    public-operation:
      description: Safe operation
      steps:
        - sub: get-secret
          => secret
        - curl -H "Authorization: {{secret}}" https://api.example.com
  1. Validate inputs:
dyngle:
  operations:
    deploy:
      description: Deploy to environment
      expressions:
        valid-env: "args[0] if args[0] in ['staging', 'production'] else None"
      steps:
        - echo "Deploying to {{valid-env}}"
  1. Limit operation scope:
  • Don't expose operations that can modify critical systems
  • Consider read-only operations for MCP exposure
  • Use private sub-operations for sensitive steps

Secrets Management

Avoid Hardcoded Secrets

Bad:

dyngle:
  values:
    api-key: secret-key-123  # Never do this

Better:

dyngle:
  operations:
    get-api-key:
      access: private
      return: key
      steps:
        - aws secretsmanager get-secret-value --secret-id api-key => secret
        - secret -> jq -r '.SecretString' => key

Use Private Operations

Operations that handle secrets should be private:

dyngle:
  operations:
    fetch-credentials:
      access: private
      return: creds
      steps:
        - # Fetch from secure source
    
    authenticated-operation:
      steps:
        - sub: fetch-credentials
          => creds
        - # Use credentials

This prevents:

  • Direct execution via dyngle run
  • Exposure via dyngle list-operations
  • Access through MCP server

Input Validation

Data from stdin

Data piped to operations should be validated:

dyngle:
  operations:
    process-user-data:
      expressions:
        validated-email: "email if '@' in email else '[email protected]'"
      steps:
        - echo "Processing: {{validated-email}}"

Command Arguments

Arguments passed to operations should be validated:

dyngle:
  operations:
    deploy:
      expressions:
        environment: "args[0] if args and args[0] in ['dev', 'staging', 'prod'] else None"
      steps:
        - echo "Deploying to {{environment}}"

General Best Practices

  1. Principle of Least Privilege:

    • Only expose necessary operations publicly
    • Use private operations for internal logic
    • Limit MCP tool exposure
  2. Configuration Management:

    • Store configurations in version control (without secrets)
    • Use separate configs for different environments
    • Protect configuration files with appropriate permissions
  3. Secret Handling:

    • Never hardcode secrets
    • Use secret management services (AWS Secrets Manager, etc.)
    • Keep secret-handling operations private
  4. Input Validation:

    • Validate all external inputs
    • Use expressions to sanitize data
    • Set reasonable defaults
  5. Audit and Monitor:

    • Review operations before exposing via MCP
    • Monitor operation execution in production
    • Keep audit logs when appropriate

Reporting Security Issues

If you discover a security vulnerability in Dyngle, please report it through the appropriate channels rather than creating public issues.

Next Steps