This document describes the security features and best practices for the OpenCTEM SDK.
The SDK provides secure credential storage with multiple protection layers.
All credential keys are validated to prevent path traversal and injection attacks:
import "github.com/openctemio/sdk/pkg/credentials"
// Keys are automatically validated
err := credentials.ValidateKey("my.api.key") // OK
err := credentials.ValidateKey("../etc/passwd") // Error: path traversal not allowed
err := credentials.ValidateKey("key@#$") // Error: invalid charactersValidation rules:
- Keys must be 1-256 characters
- Only alphanumeric characters, dots, underscores, and hyphens allowed
- Cannot start with dot or hyphen
- Path traversal sequences (
..,/,\) are rejected
For sensitive credentials, use EncryptedFileStore with AES-256-GCM encryption:
import "github.com/openctemio/sdk/pkg/credentials"
// Create encryption key (32 bytes for AES-256)
key := make([]byte, 32)
crypto_rand.Read(key)
encryptor, err := credentials.NewAESEncryptor(key)
if err != nil {
log.Fatal(err)
}
store, err := credentials.NewEncryptedFileStore("/secure/path/creds.enc", encryptor)
if err != nil {
log.Fatal(err)
}
// Credentials are encrypted at rest
store.Set(ctx, "api.token", &credentials.Credential{
Type: credentials.CredentialTypeAPIKey,
Value: "secret-token",
})Features:
- AES-256-GCM authenticated encryption
- Random nonce per encryption (prevents pattern analysis)
- Automatic key validation on all operations
SecureClear()for zeroing credentials in memory
Use constant-time comparison for credential verification to prevent timing attacks:
import "github.com/openctemio/sdk/pkg/credentials"
// Timing-safe comparison
if credentials.SecureCompare(providedToken, expectedToken) {
// Tokens match
}The gRPC transport includes multiple security features.
import "github.com/openctemio/sdk/pkg/transport/grpc"
transport := grpc.NewTransport(&grpc.Config{
Address: "grpc.openctem.io:9090",
UseTLS: true, // Always use TLS in production
// InsecureSkipVerify should be false in production
// When true, a warning is logged
InsecureSkipVerify: false,
})Security features:
- Minimum TLS 1.2 enforced
- Proper ServerName validation for certificate verification
- Security warnings logged when using insecure configurations
Validate server addresses to prevent SSRF attacks:
import "github.com/openctemio/sdk/pkg/transport/grpc"
err := grpc.ValidateAddress("grpc.example.com:9090") // OK
err := grpc.ValidateAddress("file:///etc/passwd") // Error: invalid scheme
err := grpc.ValidateAddress("unix:///var/run/sock") // Error: invalid scheme
err := grpc.ValidateAddress("0.0.0.0:9090") // Error: binding addressPlatform agents now include comprehensive security controls.
All jobs are validated before execution:
import "github.com/openctemio/sdk/pkg/platform"
config := &platform.PollerConfig{
// Restrict allowed job types
AllowedJobTypes: []string{"scan", "collect"},
// Limit payload size (default: 10MB)
MaxPayloadSize: 10 * 1024 * 1024,
// Require auth tokens on all jobs
RequireAuthToken: true,
// Validate JWT tenant claims match job tenant
ValidateTokenClaims: true,
}Validation checks:
- Job ID, tenant ID, and type are required
- Job type must be in whitelist (if configured)
- Payload size limits enforced
- Auth token validation with JWT claim matching
- Timeout validation (max 1 hour)
Lease identities are now cryptographically secured to prevent hijacking:
import "github.com/openctemio/sdk/pkg/platform"
config := &platform.LeaseConfig{
// Secure identity enabled by default
// Format: prefix-hostname-pid-<32-char-random-hex>
UseSecureIdentity: nil, // nil = true (default)
// Optional prefix for identification
IdentityPrefix: "scanner",
}Security features:
- 16-byte cryptographic random nonce in identity
- Cannot be guessed or forged by attackers
- Automatic job cancellation on lease expiry
Jobs are automatically cancelled when lease expires:
poller := platform.NewJobPoller(client, executor, config)
poller.SetLeaseManager(leaseManager)
// When lease expires:
// 1. All running jobs are cancelled via context
// 2. Jobs report "canceled" status
// 3. OnLeaseExpired callback is invokedCustom scan templates are validated to prevent attacks.
import "github.com/openctemio/sdk/pkg/core"
// Templates are automatically validated
err := core.ValidateTemplate(&core.EmbeddedTemplate{
ID: "my-template",
Name: "sql-injection.yaml", // Must be simple filename
TemplateType: "nuclei", // Must be: nuclei, semgrep, gitleaks
Content: templateContent,
ContentHash: "sha256:...", // Optional integrity check
})Validation rules:
- Path traversal in names rejected (
../,/,\) - Hidden files (starting with
.) rejected - Template type must be whitelisted
- Max 50 templates per command
- Max 1MB per template
- Content hash verification (if provided)
- Duplicate filename detection
// DO: Use encrypted storage in production
store, _ := credentials.NewEncryptedFileStore(path, encryptor)
// DO: Clear credentials when done
defer credentials.SecureClear(cred)
// DON'T: Store credentials in plain files
store := credentials.NewFileStore(path) // Only for non-sensitive data// DO: Always use TLS in production
transport := grpc.NewTransport(&grpc.Config{
UseTLS: true,
})
// DO: Validate addresses from external input
if err := grpc.ValidateAddress(userProvidedAddress); err != nil {
return err
}
// DON'T: Skip TLS verification
transport := grpc.NewTransport(&grpc.Config{
InsecureSkipVerify: true, // SECURITY WARNING logged
})// DO: Restrict allowed job types
config := &platform.PollerConfig{
AllowedJobTypes: []string{"scan"},
RequireAuthToken: true,
ValidateTokenClaims: true,
}
// DO: Use secure lease identity (default)
leaseConfig := &platform.LeaseConfig{
IdentityPrefix: "scanner", // Identify agent type
}
// DON'T: Disable security features
useSecure := false
leaseConfig := &platform.LeaseConfig{
UseSecureIdentity: &useSecure, // Only for testing
}# DO: Use environment variables for secrets
export OPENCTEMIO_API_KEY="your-api-key"
export OPENCTEMIO_ENCRYPTION_KEY="base64-encoded-key"
# DON'T: Commit secrets to version control
# api_key: "sk_live_xxxxx" # Never do this!- Using
EncryptedFileStorefor sensitive data - Encryption key stored securely (not in config files)
-
SecureClear()called after credential use - Key validation enabled (automatic)
- TLS enabled for production
-
InsecureSkipVerifyisfalse - Server addresses validated before use
-
AllowedJobTypesconfigured (whitelist) -
RequireAuthTokenenabled -
ValidateTokenClaimsenabled - Secure lease identity enabled (default)
- Lease expiry callback handles graceful shutdown
- Template validation enabled (automatic)
- Content hashes verified (if provided)
- Template directory properly sandboxed
Please report security vulnerabilities to: security@openctem.io
Do not disclose security issues publicly until a fix is available.