Getting it into your agent
One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.
git clone --depth 1 https://github.com/jakerains/CitrusRulesWrote this? Show the measurements
A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.
[](https://agentmods.dev/rules/jakerains/citrusrules/security)<a href="https://agentmods.dev/rules/jakerains/citrusrules/security"><img src="https://agentmods.dev/badge/rules/jakerains/citrusrules/security/github.svg" alt="Measured on agentmods" height="20"></a>Or the 80×15 button, for a site that already has a row of RSS and ATOM ones. Only the verdict fits; the numbers stay here.
<a href="https://agentmods.dev/rules/jakerains/citrusrules/security"><img src="https://agentmods.dev/badge/rules/jakerains/citrusrules/security.svg" alt="Reviewed on agentmods" width="80" height="20"></a>What it costs to keep this loaded
Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.
| Model | Per session | Once invoked |
|---|---|---|
| Fable 5.1 | $0.00022 | $0.04951 |
| Opus 5.5 | $0.00009 | $0.01980 |
| Sonnet 5.5 | $0.00004 | $0.00990 |
| Haiku 4.5 | $0.00002 | $0.00495 |
Grade A, and why
SecurityStandards scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 2mo ago.
A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.
Nothing flagged
None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.
How it starts
The opening of the file, as written. The whole thing — 710 lines — stays where its author put it; the contents beside it link to each section on GitHub.
Security Standards
Implement security-first development practices with comprehensive threat protection, input validation, secure authentication, and data protection. This rule ensures all code follows security best practices and prevents common vulnerabilities.
Security-First Development Process
For every feature implementation, I will:
- Threat Assessment: Identify potential security risks and attack vectors
- Input Analysis: Catalog all user inputs and data sources requiring validation
- Authentication Review: Ensure proper authentication and authorization controls
- Data Protection: Implement encryption, sanitization, and secure data handling
- Security Testing: Validate security measures and test for vulnerabilities
- Monitoring Setup: Implement security logging and monitoring
Core Security Implementation Patterns
1. Comprehensive Input Validation Template
Use this pattern for all user input handling:
import { z } from 'zod';
import DOMPurify from 'dompurify';
import rateLimit from 'express-rate-limit';
// Schema-based validation with security constraints
const SecureUserInputSchema = z.object({
email: z.string()
.email('Invalid email format')
.max(254, 'Email too long')
.refine(email => !email.includes('<'), 'Invalid characters in email'),
password: z.string()
.min(12, 'Password must be at least 12 characters')
.max(128, 'Password too long')
.regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]/,
'Password must contain uppercase, lowercase, number, and special character'),
name: z.string()
.min(1, 'Name is required')
.max(100, 'Name too long')
.regex(/^[a-zA-Z\s\-'\.]+$/, 'Name contains invalid characters'),
content: z.string()
.max(5000, 'Content too long')
.transform(content => DOMPurify.sanitize(content))
});
class SecureInputValidator {
// Rate limiting middleware
static createRateLimit(windowMs: number, max: number) {
return rateLimit({
windowMs,
max,
message: { error: 'Too many requests, please try again later' },
standardHeaders: true,
legacyHeaders: false,
handler: (req, res) => {
this.logSecurityEvent('rate_limit_exceeded', {
ip: req.ip,
userAgent: req.get('User-Agent'),
endpoint: req.originalUrl
});
res.status(429).json({ error: 'Rate limit exceeded' });
}
});
}
// Comprehensive input validation
static async validateInput<T>(
schema: z.ZodSchema<T>,
input: unknown,
context: string
): Promise<T> {
try {
// Pre-validation security checks
this.performSecurityChecks(input, context);
// Schema validation
const result = await schema.parseAsync(input);
// Post-validation security verification
this.verifySecurityConstraints(result, context);
return result;
} catch (error) {
this.logSecurityEvent('input_validation_failed', {
context,
error: error.message,
input: this.sanitizeForLogging(input)
});
throw new ValidationError('Invalid input provided');
}
}
private static performSecurityChecks(input: unknown, context: string): void {
const inputStr = JSON.stringify(input);
// Check for common injection patterns
const dangerousPatterns = [
/<script/i,
/javascript:/i,
/on\w+\s*=/i,
/union\s+select/i,
/drop\s+table/i,
/exec\s*\(/i,
/eval\s*\(/i
];
for (const pattern of dangerousPatterns) {
if (pattern.test(inputStr)) {
this.logSecurityEvent('malicious_input_detected', {
context,
pattern: pattern.source,
input: this.sanitizeForLogging(input)
});
throw new SecurityError('Potentially malicious input detected');
}
}
}
private static verifySecurityConstraints<T>(result: T, context: string): void {
// Additional security checks on validated data
if (typeof result === 'object' && result !== null) {
const resultStr = JSON.stringify(result);
// Check for suspicious patterns in validated data
if (resultStr.length > 100000) {
throw new SecurityError('Input exceeds maximum size limits');
}
}
}
private static sanitizeForLogging(input: unknown): string {
const inputStr = JSON.stringify(input);
// Remove potentially sensitive data for logging
return inputStr
.replace(/("password":\s*")[^"]*"/gi, '$1[REDACTED]"')
.replace(/("token":\s*")[^"]*"/gi, '$1[REDACTED]"')
.replace(/("secret":\s*")[^"]*"/gi, '$1[REDACTED]"')
.substring(0, 500); // Limit log size
}
private static logSecurityEvent(event: string, details: Record<string, any>): void {
console.warn('SECURITY_EVENT', {
timestamp: new Date().toISOString(),
event,
...details
});
}
}
What this file has done since we first saw it
Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.
- 2mo ago First seen · 710 lines · 4,951 tokens per session scan A f9e9fcac1e46
SecurityStandards is a cursor rule published in the GitHub repository jakerains/CitrusRules (2 stars, last pushed 1y ago), licensed MIT. It adds 22 tokens to every session and 4,951 once invoked, about $0.0001 per session on Opus 5.5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-31.
Other cursor rules, from other repositories
ponytail
Ponytail, lazy senior dev mode. Always pick the simplest solution that works.
angular-20
This rule provides comprehensive best practices and coding standards for Angular development, focusing on modern TypeScript, standalone components, signals, and performance optimizations.
dev-standard
Apache Superset development standards and guidelines for Cursor IDE.
prefer-direct-imports-over-module-mocks
Prefer extracting a testable core over vi.mock / vi.resetModules when unit tests need to reach production logic entangled with config, env, or singletons.
config-validation-and-normalization
Config validation and normalization responsibilities (defineConfig normalizes, the orm section schema validates and resolves paths, the loader reports per-section diagnostics).
control-plane-descriptors
Control plane descriptor and instance implementation patterns.