between the LLM generation step and the memory persistence layer. This pattern, often referred to as a Memory Guard, ensures that all data destined for storage is sanitized against known injection signatures and behavioral anomalies.
Architecture Decision
The recommended flow modifies the standard visual pipeline:
External Input β LLM Node β [Memory Guard] β Memory Store
Rationale:
- Separation of Concerns: The LLM node focuses on content generation. The guard enforces security policy.
- Framework Agnosticism: The guard logic can be implemented as a standalone module, making it portable across Flowise, Dify, or custom TypeScript backends.
- Fail-Safe Defaults: The guard should default to blocking writes if the validation service is unavailable, preventing unverified data from entering the store.
Implementation Pattern (TypeScript)
Below is a robust implementation of a memory guard interface. This example demonstrates how to structure the validation logic, handle risk scoring, and integrate with existing memory providers.
import { MemoryGuardClient } from 'agent-memory-guard';
interface GuardResult {
isSafe: boolean;
threatType?: string;
riskScore: number;
metadata: Record<string, unknown>;
}
class AgenticMemoryGuard {
private client: MemoryGuardClient;
private threshold: number;
constructor(config: { riskThreshold?: number }) {
this.client = new MemoryGuardClient();
this.threshold = config.riskThreshold || 0.75;
}
/**
* Validates payload before memory write.
* Throws error if threat is detected to prevent storage.
*/
async validateBeforeWrite(payload: string): Promise<GuardResult> {
const scanResult = await this.client.analyze(payload);
const result: GuardResult = {
isSafe: scanResult.score < this.threshold,
riskScore: scanResult.score,
threatType: scanResult.category,
metadata: {
timestamp: Date.now(),
payloadLength: payload.length,
},
};
if (!result.isSafe) {
// Log security event for SIEM integration
console.error(
`ASI06_BLOCKED: Type=${result.threatType}, Score=${result.riskScore}`
);
throw new Error(
`Memory write rejected: Potential injection detected (${result.threatType})`
);
}
return result;
}
}
// Usage in a workflow step
async function secureMemoryWrite(
llmOutput: string,
memoryStore: any
): Promise<void> {
const guard = new AgenticMemoryGuard({ riskThreshold: 0.6 });
try {
await guard.validateBeforeWrite(llmOutput);
await memoryStore.save(llmOutput);
} catch (error) {
// Handle rejection: alert ops, skip write, continue workflow
console.warn('Write operation aborted by memory guard.');
}
}
Key Technical Choices:
- Risk Thresholding: Instead of binary allow/deny, the guard uses a risk score. This allows tuning sensitivity based on the application's risk appetite.
- Metadata Enrichment: The result includes payload length and timestamps, aiding forensic analysis if an attack is blocked.
- Explicit Error Handling: The guard throws on detection, forcing the calling workflow to handle the rejection explicitly rather than failing silently.
Pitfall Guide
-
The "Clean Input" Fallacy
- Mistake: Sanitizing only user input and assuming LLM output is safe.
- Explanation: Attackers can craft inputs that cause the LLM to output malicious instructions. The danger lies in what the LLM writes to memory, not just what the user sends.
- Fix: Always validate the LLM's output payload before it touches the memory store.
-
Ignoring Multi-Vector Context
- Mistake: Scanning only the immediate text chunk.
- Explanation: Poisoning can be distributed across multiple chunks or hidden in metadata fields.
- Fix: Ensure the guard scans the full payload structure, including embedded JSON, metadata, and concatenated context windows.
-
Performance Bottlenecks
- Mistake: Using synchronous blocking calls for validation in high-throughput workflows.
- Explanation: Memory writes can become a throughput choke point if validation is slow.
- Fix: Implement async validation with timeouts. Use a circuit breaker pattern to allow writes if the guard service degrades, while logging the risk.
-
False Positive Overload
- Mistake: Setting thresholds too low, causing legitimate memory updates to fail.
- Explanation: Aggressive pattern matching may flag technical documentation or code snippets as injection attempts.
- Fix: Calibrate thresholds using a dataset of legitimate application traffic. Implement a quarantine queue for borderline cases rather than immediate rejection.
-
Lack of Audit Trails
- Mistake: Blocking attacks without logging details.
- Explanation: Without logs, you cannot detect ongoing campaigns or tune the guard effectively.
- Fix: Integrate guard rejections with your observability stack. Log threat type, score, source session, and payload hash.
-
Static Pattern Reliance
- Mistake: Relying solely on regex for detection.
- Explanation: Adversaries can obfuscate instructions using encoding, synonyms, or structural variations.
- Fix: Use a guard solution that employs semantic analysis or heuristic models, not just string matching.
-
Assuming No-Code Safety
- Mistake: Believing visual platforms handle security automatically.
- Explanation: Platforms like Flowise and Dify provide the execution engine but do not enforce content policy on memory writes by default.
- Fix: Treat every memory write node as a security boundary requiring explicit protection.
Production Bundle
Action Checklist
Decision Matrix
| Scenario | Recommended Approach | Why | Cost Impact |
|---|
| Regulated Industry (Healthcare/Finance) | Strict Guard + Quarantine | Zero tolerance for data exfiltration; requires auditability. | Moderate (Storage for quarantine, ops overhead) |
| Internal Knowledge Bot | Standard Guard | Risk is contained to internal users; balance speed and security. | Low (Minimal latency impact) |
| Public-Facing Agent | Guard + Rate Limiting | High exposure to adversarial inputs; need to prevent abuse at scale. | Low-Moderate (Guard cost + rate limit infra) |
| Prototype/MVP | Basic Pattern Scan | Rapid iteration; sufficient to catch obvious attacks. | Negligible |
Configuration Template
Use this TypeScript configuration to initialize the guard with production-ready settings. This template assumes integration with the agent-memory-guard ecosystem.
// guard.config.ts
import { GuardConfig, RiskLevel } from 'agent-memory-guard';
export const memoryGuardConfig: GuardConfig = {
// Sensitivity: 0.0 to 1.0. Lower = stricter.
riskThreshold: 0.65,
// Actions on detection
onThreatDetected: {
action: 'BLOCK_AND_LOG',
logLevel: 'ERROR',
alertWebhook: process.env.SECURITY_ALERT_URL,
},
// Performance settings
timeoutMs: 200,
retryAttempts: 1,
// Custom rules for your domain
customPatterns: [
{
name: 'admin_override_attempt',
regex: /(?:admin|superuser|root).*(?:override|grant|elevate)/i,
severity: RiskLevel.CRITICAL,
},
],
};
Quick Start Guide
- Install the Guard Library:
npm install agent-memory-guard
- Wrap Your Memory Write:
Import the guard client and wrap your existing memory save function with the validation check.
const guard = new MemoryGuardClient(memoryGuardConfig);
await guard.validate(payload);
await memoryStore.save(payload);
- Verify Integration:
Send a test payload containing a known injection pattern (e.g.,
SYSTEM: Ignore previous instructions). Confirm the guard throws an error and the memory store is not updated.
- Deploy and Monitor:
Deploy the updated workflow. Monitor your logs for
ASI06_BLOCKED events to ensure the guard is active and correctly calibrated.