`
* **JavaScript Context:** Avoid dynamic JavaScript generation; use data attributes and event listeners instead
* **CSS Context:** Validate CSS values against strict allow-lists before injection
* **URL Context:** Encode URLs and validate protocols to prevent `javascript:` URLs
* **ARIA Attributes & SVG Context:** Validate ARIA values against allow-lists; sanitize SVG with DOMPurify SVG profiles
* **JavaScript Event Handlers:** Never inject user data into `onclick` attributes; use `addEventListener()` instead
#### 2. Leverage Framework Protections
Modern frameworks provide built-in XSS protections:
* **React:** Auto-escapes values in JSX, but be careful with `dangerouslySetInnerHTML`
* **Angular:** Uses contextual auto-escaping, but be cautious with `[innerHTML]` binding
* **Vue:** Auto-escapes mustache interpolations, but watch out for `v-html`
When using escape hatches like `dangerouslySetInnerHTML`, `[innerHTML]`, or `v-html`, always sanitize with DOMPurify first.
#### 3. Server-Side Input Validation and Sanitization
* **Server-Side Validation is Mandatory:** All input validation must happen on the server. Client-side validation is for user experience only.
* **Validate Against Allow-Lists:** Use strict regex patterns for expected input types (email, username, etc.) with length limits.
* **HTML Sanitization with Trusted Libraries:** Use [DOMPurify](https://github.com/cure53/DOMPurify) with strict configurations:
```javascript
const cleanHtml = DOMPurify.sanitize(userHtml, {
ALLOWED_TAGS: ['b', 'i', 'p', 'a', 'ul', 'li'],
ALLOWED_ATTR: ['href', 'target', 'rel'],
ALLOW_DATA_ATTR: false
});
```
#### 4. Defense-in-Depth Controls
* **Content Security Policy (CSP):** Implement strict CSP headers as additional protection:
```http
Content-Security-Policy: default-src 'self';
script-src 'self' 'nonce-{random}';
style-src 'self' 'unsafe-inline';
object-src 'none';
base-uri 'self';
require-trusted-types-for 'script';
```
* **Trusted Types API:** Use Trusted Types to prevent DOM XSS:
```javascript
// Define trusted types policy
const policy = trustedTypes.createPolicy('myPolicy', {
createHTML: (string) => DOMPurify.sanitize(string),
createScript: () => { throw new Error('Script creation not allowed'); }
});
// Use with trusted types
element.innerHTML = policy.createHTML(userInput);
```
* **Safe DOM APIs:** Always prefer safe DOM manipulation methods:
```javascript
// Safe approaches
element.textContent = userInput; // Always safe for text
element.setAttribute('data-user', userInput); // Safe for most attributes
element.classList.add(validatedClassName); // Safe for CSS classes
```
* **Secure Cookie Configuration:** Prevent cookie theft:
```http
Set-Cookie: sessionId=abc123; HttpOnly; Secure; SameSite=Strict
```
#### 5. Common Pitfalls to Avoid
* **Don't trust any data source:** Even internal APIs or databases can contain malicious data.
* **Beware of indirect inputs:** User data can enter your application through URLs, form fields, HTTP headers, and JSON/XML payloads.
* **Don't rely on client-side sanitization alone:** Always re-validate and sanitize on the server.
* **Keep dependencies updated:** Regularly update your frameworks and libraries to benefit from security patches.
By applying these context-specific encoding strategies and defense-in-depth approaches, you can significantly reduce the risk of XSS vulnerabilities in your web applications.
================================================
FILE: sources/owasp/codeguard-0-cryptographic-storage.md
================================================
---
description: Cryptographic Storage Best Practices
languages:
- c
- go
- java
- javascript
- kotlin
- matlab
- python
- ruby
- swift
- typescript
alwaysApply: false
---
## Introduction
This rule provides a simple model to follow when implementing solutions to protect data at rest.
Passwords should not be stored using reversible encryption - secure password hashing algorithms should be used instead. The [Password Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html) contains further guidance on storing passwords.
## Rule 1: Architectural Design Requirements
**YOU MUST consider the overall architecture** of the system, as this will have a huge impact on the technical implementation.
* **Application level** - REQUIRED for database compromise protection
* **Database level** (SQL Server TDE) - Additional data-at-rest protection
* **Filesystem level** (BitLocker, LUKS) - Physical theft protection
* **Hardware level** (encrypted RAID/SSDs) - Hardware-based protection
**YOU MUST minimize sensitive data storage** - avoid storing credit card details and implement data minimization policies. Use tokenization when storage is unavoidable.
## Rule 2: Algorithm Requirements
**YOU MUST use approved algorithms:**
* **Symmetric:** AES with ≥128-bit keys (256-bit preferred)
* **Asymmetric:** Curve25519 (ECC preferred) or RSA ≥2048 bits
* **Custom algorithms:** PROHIBITED
**YOU MUST use authenticated cipher modes:**
1. **GCM** or **CCM** (preferred)
2. **CTR/CBC** only with separate authentication (Encrypt-then-MAC)
3. **ECB:** PROHIBITED
**For RSA: YOU MUST enable Random Padding** (OAEP/PKCS#1).
**YOU MUST use cryptographically secure random generators:**
| Platform | PROHIBITED | REQUIRED |
|----------|------------|----------|
| PHP | `rand()`, `mt_rand()` | `random_bytes()`, `random_int()` |
| Java | `java.util.Random` | `java.security.SecureRandom` |
| .NET | `System.Random` | `System.Security.Cryptography.RandomNumberGenerator` |
| Python | `random` module | `secrets` module |
| JavaScript | `Math.random()` | `window.crypto.getRandomValues()` |
| Go | `math/rand` | `crypto/rand` |
| Node.js | `Math.random()` | `crypto.randomBytes()`, `crypto.randomInt()` |
**UUIDs:** Version 1 UUIDs are NOT random. Only trust Version 4 UUIDs if implementation uses CSPRNG.
## Rule 3: Key Management Requirements
**YOU MUST implement formal processes for:**
* Key generation using cryptographically secure functions
* Secure key distribution and deployment
* Regular key rotation and secure decommissioning
**Key Generation:** YOU ARE PROHIBITED from using passwords, phrases, or predictable patterns. Multiple keys MUST be fully independent.
**Key Rotation Requirements - YOU MUST rotate keys when:**
* Key compromise is suspected
* Cryptoperiod expires (see NIST SP 800-57)
* Usage limits reached (2^35 bytes for 64-bit keys, 2^68 bytes for 128-bit)
* Algorithm security changes
**YOU MUST have rotation processes ready BEFORE compromise.**
## Rule 4: Key Storage Requirements
**YOU MUST use secure storage mechanisms where available:**
* Physical/Virtual HSMs
* Cloud key vaults (AWS KMS, Azure Key Vault, Google Cloud KMS)
* External secrets management (HashiCorp Vault, Conjur)
* Framework secure APIs (ProtectedData, Keychain)
**Basic Storage Rules (when secure mechanisms unavailable):**
* PROHIBITED: Hard-coding keys in source code or version control
* REQUIRED: Restrictive permissions on config files
* AVOID: Environment variables (exposure risk)
**Key Separation:** YOU MUST store keys separately from encrypted data where possible.
**Key Encryption:** YOU MUST encrypt stored keys using separate Key Encryption Keys (KEK):
* Data Encryption Key (DEK) encrypts data
* Key Encryption Key (KEK) encrypts DEK
* KEK MUST be stored separately and be ≥ as strong as DEK
## Rule 5: Defense in Depth Requirements
**YOU MUST design applications to be secure even if cryptographic controls fail:**
* Additional security layers for encrypted information
* Strong access control (not relying on encrypted URL parameters alone)
* Logging and monitoring of encrypted data access
## Critical Security Requirements
**COMPLIANCE IS MANDATORY** for all systems handling sensitive data.
**YOU ARE ABSOLUTELY PROHIBITED FROM:**
* Implementing custom cryptographic algorithms
* Using insecure random generators for security purposes
* Hard-coding encryption keys in source code
* Using deprecated algorithms (MD5, SHA-1, DES, RC4)
* Storing keys with encrypted data without proper separation
**YOU MUST ALWAYS:**
* Use authenticated encryption modes where available
* Generate unique, random keys for each operation
* Implement proper key lifecycle management
* Use vetted cryptographic libraries only
* Test key rotation procedures before needed
================================================
FILE: sources/owasp/codeguard-0-cw-cryptographic-security-guidelines.md
================================================
---
description: Cryptographic Security Guidelines
languages:
- c
alwaysApply: false
---
### Cryptographic Security Guidelines
#### Deprecated SSL/Crypto APIs - FORBIDDEN
**NEVER use these deprecated functions. Use the replacement APIs listed below:**
##### Symmetric Encryption (AES)
- **Deprecated**: `AES_encrypt()`, `AES_decrypt()`
- **Replacement**: Use EVP high-level APIs:
```c
EVP_EncryptInit_ex()
EVP_EncryptUpdate()
EVP_EncryptFinal_ex()
EVP_DecryptInit_ex()
EVP_DecryptUpdate()
EVP_DecryptFinal_ex()
```
##### RSA Operations
- **Deprecated**: `RSA_new()`, `RSA_up_ref()`, `RSA_free()`, `RSA_set0_crt_params()`, `RSA_get0_n()`
- **Replacement**: Use EVP key management APIs:
```c
EVP_PKEY_new()
EVP_PKEY_up_ref()
EVP_PKEY_free()
```
##### Hash Functions
- **Deprecated**: `SHA1_Init()`, `SHA1_Update()`, `SHA1_Final()`
- **Replacement**: Use EVP digest APIs:
```c
EVP_DigestInit_ex()
EVP_DigestUpdate()
EVP_DigestFinal_ex()
EVP_Q_digest() // For simple one-shot hashing
```
##### MAC Operations
- **Deprecated**: `CMAC_Init()`, `HMAC()` (especially with SHA1)
- **Replacement**: Use EVP MAC APIs:
```c
EVP_Q_MAC() // For simple MAC operations
```
##### Key Wrapping
- **Deprecated**: `AES_wrap_key()`, `AES_unwrap_key()`
- **Replacement**: Use EVP key wrapping APIs or implement using EVP encryption
##### Other Deprecated Functions
- **Deprecated**: `DSA_sign()`, `DH_check()`
- **Replacement**: Use corresponding EVP APIs for DSA and DH operations
#### Banned Insecure Algorithms - STRICTLY FORBIDDEN
**These algorithms MUST NOT be used in any form:**
##### Hash Algorithms (Banned)
- MD2, MD4, MD5, SHA-0
- **Reason**: Cryptographically broken, vulnerable to collision attacks
- **Use Instead**: SHA-256, SHA-384, SHA-512
##### Symmetric Ciphers (Banned)
- RC2, RC4, Blowfish, DES, 3DES
- **Reason**: Weak key sizes, known vulnerabilities
- **Use Instead**: AES-128, AES-256, ChaCha20
##### Key Exchange (Banned)
- Static RSA key exchange
- Anonymous Diffie-Hellman
- **Reason**: No forward secrecy, vulnerable to man-in-the-middle attacks
- **Use Instead**: ECDHE, DHE with proper validation
#### Broccoli Project Specific Requirements
- **HMAC() with SHA1**: Deprecated per Broccoli project requirements
- **Replacement**: Use HMAC with SHA-256 or stronger:
```c
// Instead of HMAC() with SHA1
EVP_Q_MAC(NULL, "HMAC", NULL, "SHA256", NULL, key, key_len, data, data_len, out, out_size, &out_len);
```
#### Secure Crypto Implementation Pattern
```c
// Example: Secure AES encryption
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (!ctx) handle_error();
if (EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, key, iv) != 1)
handle_error();
int len, ciphertext_len;
if (EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len) != 1)
handle_error();
ciphertext_len = len;
if (EVP_EncryptFinal_ex(ctx, ciphertext + len, &len) != 1)
handle_error();
ciphertext_len += len;
EVP_CIPHER_CTX_free(ctx);
```
#### Code Review Checklist
- [ ] No deprecated SSL/crypto APIs used
- [ ] No banned algorithms (MD5, DES, RC4, etc.)
- [ ] HMAC uses SHA-256 or stronger (not SHA1)
- [ ] All crypto operations use EVP high-level APIs
- [ ] Proper error handling for all crypto operations
- [ ] Key material properly zeroed after use
================================================
FILE: sources/owasp/codeguard-0-cw-memory-string-usage-guidelines.md
================================================
---
description: Memory and String Safety Guidelines
languages:
- c
alwaysApply: false
---
### Memory and String Safety Guidelines
#### Unsafe Memory Functions - FORBIDDEN
**NEVER use these unsafe memory functions that don't check input parameter boundaries:**
##### Banned Memory Functions:
- `memcpy()` → Use `memcpy_s()`
- `memset()` → Use `memset_s()`
- `memmove()` → Use `memmove_s()`
- `memcmp()` → Use `memcmp_s()`
- `bzero()` → Use `memset_s()`
- `memzero()` → Use `memset_s()`
##### Safe Memory Function Replacements:
```c
// Instead of: memcpy(dest, src, count);
errno_t result = memcpy_s(dest, dest_size, src, count);
if (result != 0) {
// Handle error
}
// Instead of: memset(dest, value, count);
errno_t result = memset_s(dest, dest_size, value, count);
// Instead of: memmove(dest, src, count);
errno_t result = memmove_s(dest, dest_size, src, count);
// Instead of: memcmp(s1, s2, count);
int indicator;
errno_t result = memcmp_s(s1, s1max, s2, s2max, count, &indicator);
if (result == 0) {
// indicator contains comparison result: <0, 0, or >0
}
```
#### Unsafe String Functions - FORBIDDEN
**NEVER use these unsafe string functions that can cause buffer overflows:**
##### Banned String Functions:
- `strstr()` → Use `strstr_s()`
- `strtok()` → Use `strtok_s()`
- `strcpy()` → Use `strcpy_s()`
- `strcmp()` → Use `strcmp_s()`
- `strlen()` → Use `strnlen_s()`
- `strcat()` → Use `strcat_s()`
- `sprintf()` → Use `snprintf()`
##### Safe String Function Replacements:
```c
// String Search
errno_t strstr_s(char *dest, rsize_t dmax, const char *src, rsize_t slen, char **substring);
// String Tokenization
char *strtok_s(char *dest, rsize_t *dmax, const char *src, char **ptr);
// String Copy
errno_t strcpy_s(char *dest, rsize_t dmax, const char *src);
// String Compare
errno_t strcmp_s(const char *dest, rsize_t dmax, const char *src, int *indicator);
// String Length (bounded)
rsize_t strnlen_s(const char *str, rsize_t strsz);
// String Concatenation
errno_t strcat_s(char *dest, rsize_t dmax, const char *src);
// Formatted String (always use size-bounded version)
int snprintf(char *s, size_t n, const char *format, ...);
```
#### Implementation Examples:
##### Safe String Copy Pattern:
```c
// Bad - unsafe
char dest[256];
strcpy(dest, src); // Buffer overflow risk!
// Good - safe
char dest[256];
errno_t result = strcpy_s(dest, sizeof(dest), src);
if (result != 0) {
// Handle error: src too long or invalid parameters
EWLC_LOG_ERROR("String copy failed: %d", result);
return ERROR;
}
```
##### Safe String Concatenation Pattern:
```c
// Bad - unsafe
char buffer[256] = "prefix_";
strcat(buffer, suffix); // Buffer overflow risk!
// Good - safe
char buffer[256] = "prefix_";
errno_t result = strcat_s(buffer, sizeof(buffer), suffix);
if (result != 0) {
EWLC_LOG_ERROR("String concatenation failed: %d", result);
return ERROR;
}
```
##### Safe Memory Copy Pattern:
```c
// Bad - unsafe
memcpy(dest, src, size); // No boundary checking!
// Good - safe
errno_t result = memcpy_s(dest, dest_max_size, src, size);
if (result != 0) {
EWLC_LOG_ERROR("Memory copy failed: %d", result);
return ERROR;
}
```
##### Safe String Tokenization Pattern:
```c
// Bad - unsafe
char *token = strtok(str, delim); // Modifies original string unsafely
// Good - safe
char *next_token = NULL;
rsize_t str_max = strnlen_s(str, MAX_STRING_SIZE);
char *token = strtok_s(str, &str_max, delim, &next_token);
while (token != NULL) {
// Process token
token = strtok_s(NULL, &str_max, delim, &next_token);
}
```
#### Memory and String Safety Code Review Checklist:
##### Pre-Code Review (Developer):
- [ ] No unsafe memory functions (`memcpy`, `memset`, `memmove`, `memcmp`, `bzero`)
- [ ] No unsafe string functions (`strcpy`, `strcat`, `strcmp`, `strlen`, `sprintf`, `strstr`, `strtok`)
- [ ] All memory operations use `*_s()` variants with proper size parameters
- [ ] Buffer sizes are correctly calculated using `sizeof()` or known limits
- [ ] No hardcoded buffer sizes that could change
##### Code Review (Reviewer):
- [ ] **Memory Safety**: Verify all memory operations use safe variants
- [ ] **Buffer Bounds**: Confirm destination buffer sizes are properly specified
- [ ] **Error Handling**: Check that all `errno_t` return values are handled
- [ ] **Size Parameters**: Validate that `rsize_t dmax` parameters are correct
- [ ] **String Termination**: Ensure strings are properly null-terminated
- [ ] **Length Validation**: Check that source string lengths are validated before operations
##### Static Analysis Integration:
- [ ] Enable compiler warnings for unsafe function usage
- [ ] Use static analysis tools to detect unsafe function calls
- [ ] Configure build system to treat unsafe function warnings as errors
- [ ] Add pre-commit hooks to scan for banned functions
#### Common Pitfalls and Solutions:
##### Pitfall 1: Wrong Size Parameter
```c
// Wrong - using source size instead of destination size
strcpy_s(dest, strlen(src), src); // WRONG!
// Correct - using destination buffer size
strcpy_s(dest, sizeof(dest), src); // CORRECT
```
##### Pitfall 2: Ignoring Return Values
```c
// Wrong - ignoring potential errors
strcpy_s(dest, sizeof(dest), src); // Error not checked
// Correct - checking return value
if (strcpy_s(dest, sizeof(dest), src) != 0) {
// Handle error appropriately
}
```
##### Pitfall 3: Using sizeof() on Pointers
```c
// Wrong - sizeof pointer, not buffer
void func(char *buffer) {
strcpy_s(buffer, sizeof(buffer), src); // sizeof(char*) = 8!
}
// Correct - pass buffer size as parameter
void func(char *buffer, size_t buffer_size) {
strcpy_s(buffer, buffer_size, src);
}
```
================================================
FILE: sources/owasp/codeguard-0-database-security.md
================================================
---
description: Database Security Best Practices
languages:
- c
- java
- javascript
- python
- sql
- yaml
alwaysApply: false
---
## Database Security Guidelines
This rule advises on securely configuring SQL and NoSQL databases to protect against data breaches and unauthorized access:
- Backend Database Protection
- Isolate database servers from other systems and limit host connections.
- Disable network (TCP) access when possible; use local socket files or named pipes.
- Configure database to bind only on localhost when appropriate.
- Restrict network port access to specific hosts with firewall rules.
- Place database server in separate DMZ isolated from application server.
- Never allow direct connections from thick clients to backend database.
- Transport Layer Security
- Configure database to only allow encrypted connections.
- Install trusted digital certificates on database servers.
- Use TLSv1.2+ with modern ciphers (AES-GCM, ChaCha20) for client connections.
- Verify digital certificate validity in client applications.
- Ensure all database traffic is encrypted, not just initial authentication.
- Secure Authentication Configuration
- Always require authentication, including from local server connections.
- Protect accounts with strong, unique passwords.
- Use dedicated accounts per application or service.
- Configure minimum required permissions only.
- Regularly review accounts and permissions.
- Remove accounts when applications are decommissioned.
- Change passwords when staff leave or compromise is suspected.
- Database Credential Storage
- Never store credentials in application source code.
- Store credentials in configuration files outside web root.
- Set appropriate file permissions for credential access.
- Never check credential files into source code repositories.
- Encrypt credential storage using built-in functionality when available.
- Use environment variables or secrets management solutions.
- Secure Permission Management
- Apply principle of least privilege to all database accounts.
- Do not use built-in root, sa, or SYS accounts.
- Do not grant administrative rights to application accounts.
- Restrict account connections to allowed hosts only.
- Use separate databases and accounts for Development, UAT, and Production.
- Grant only required permissions (SELECT, UPDATE, DELETE as needed).
- Avoid making accounts database owners to prevent privilege escalation.
- Implement table-level, column-level, and row-level permissions when needed.
- Database Configuration and Hardening
- Install required security updates and patches regularly.
- Run database services under low-privileged user accounts.
- Remove default accounts and sample databases.
- Store transaction logs on separate disk from main database files.
- Configure regular encrypted database backups with proper permissions.
- Disable unnecessary stored procedures and dangerous features.
- Implement database activity monitoring and alerting.
- Platform-Specific Hardening
- SQL Server: Disable xp_cmdshell, CLR execution, SQL Browser service, Mixed Mode Authentication (unless required).
- MySQL/MariaDB: Run mysql_secure_installation, disable FILE privilege for users.
- PostgreSQL: Follow PostgreSQL security documentation guidelines.
- MongoDB: Implement MongoDB security checklist requirements.
- Redis: Follow Redis security guide recommendations.
Summary:
Isolate database systems, enforce encrypted connections, implement strong authentication, store credentials securely using secrets management, apply least privilege permissions, harden database configurations, and maintain regular security updates and monitoring.
================================================
FILE: sources/owasp/codeguard-0-deserialization.md
================================================
---
description: Deserialization Security Best Practices
languages:
- c
- java
- javascript
- php
- python
- xml
- yaml
alwaysApply: false
---
## Avoid Unsafe Deserialization of Untrusted Data
Deserialization of untrusted input can lead to critical vulnerabilities such as remote code execution, denial of service, and privilege escalation. This rule ensures developers follow best practices to safely handle serialization and deserialization operations.
Requirements:
- Always treat incoming serialized data from untrusted sources as hostile.
- Validate input size, structure, and content before deserialization.
- Prefer standardized, safe data formats like JSON or XML without type metadata over native serialization formats.
- For XML: disable DTDs and external entities to prevent XXE attacks.
- Avoid using unsafe native serialization APIs on untrusted input, such as:
- PHP: avoid `unserialize()`, use `json_decode()`/`json_encode()` instead.
- Python: avoid `pickle.loads`, `yaml.load` (use `safe_load`), and `jsonpickle` on untrusted data.
- Java: override `ObjectInputStream#resolveClass()` to allowlist classes; mark sensitive fields `transient`; avoid polymorphic deserialization unless strictly allowlisted.
- .NET: avoid `BinaryFormatter`; use `DataContractSerializer` or `XmlSerializer`; set `TypeNameHandling = None` in JSON.Net; never trust deserialized types blindly.
- Sign serialized data and verify signatures to ensure integrity before deserialization.
- Configure serialization libraries securely:
- Jackson: `mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL)` is dangerous
- fastjson: Enable safemode, disable autotype
- XStream: Use allowlists with `XStream.allowTypes()`
- SnakeYAML: Use `yaml.safe_load()` instead of `yaml.load()`
- Keep dependencies updated to fixed versions.
- Reject or safely handle polymorphic or complex objects deserialization from untrusted sources.
- Use hardened deserialization agents/tools (e.g., SerialKiller, hardened ObjectInputStream subclasses, JVM agents).
- Log deserialization attempts and monitor for suspicious activity.
- Regularly scan code and dependencies for unsafe deserialization patterns using static and dynamic analysis tools.
Security Impact:
Deserialization attacks are a frequently exploited vector leading to severe security impacts. Following these practices prevents attackers from injecting malicious objects or payloads that the application may execute.
Examples:
Avoid:
- PHP: calling `unserialize($data)` on external input.
- Java: deserializing classes without strict allowlisting or type validation.
- Python: loading YAML with `yaml.load()` on untrusted data.
- .NET: using `BinaryFormatter.Deserialize()` on untrusted input.
- XML: processing XML with DTDs enabled or external entity resolution.
Recommended:
- PHP: use `json_decode()` and validate JSON schema.
- Java: Override `resolveClass()` to allowlist safe classes:
```java
@Override
protected Class> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
if (!allowedClasses.contains(desc.getName())) {
throw new InvalidClassException("Unauthorized class", desc.getName());
}
return super.resolveClass(desc);
}
```
- Python: Use safe YAML loading:
```python
import yaml
data = yaml.safe_load(input) # Safe
# Never: yaml.load(input) # Dangerous
```
- .NET: Use DataContractSerializer with type control:
```csharp
// Safe approach
var serializer = new DataContractSerializer(typeof(SafeType));
var obj = serializer.ReadObject(stream);
// JSON.NET safety
JsonConvert.DeserializeObject
(json, new JsonSerializerSettings {
TypeNameHandling = TypeNameHandling.None
});
```
- XML: Configure parsers safely:
```java
// Java: Disable DTDs and external entities
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
```
```csharp
// .NET: Disable DTD processing
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Prohibit;
```
Monitoring Requirements:
- Log all deserialization attempts with data size and type information
- Alert on deserialization failures or unexpected data patterns
- Monitor for known malicious payloads (e.g., `AC ED 00 05`, `rO0`, `AAEAAAD`)
- Track deserialization performance to detect "billion laughs" attacks
================================================
FILE: sources/owasp/codeguard-0-django-rest-framework.md
================================================
---
description: Django REST Framework Security Best Practices
languages:
- python
- yaml
alwaysApply: false
---
## Django REST Framework Security Guidelines
This rule advises on critical security practices when developing Django REST Framework APIs to protect against common risks:
- Authentication & Authorization
- Always set `DEFAULT_AUTHENTICATION_CLASSES` with appropriate authentication schemes for all non-public endpoints.
- When using SessionAuthentication, ensure CSRF protection is enabled and properly configured.
- Never leave `DEFAULT_PERMISSION_CLASSES` as `AllowAny`; explicitly restrict access using proper permission classes.
- When overriding `get_object()`, always call `self.check_object_permissions(request, obj)` to enforce object-level access control.
- Avoid per-view overrides of authentication, permission, or throttle classes unless fully confident in their implications.
- Serializer Security
- In DRF Serializers, specify explicit `fields = [...]` allowlists; do not use `exclude`.
- For Django ModelForms (when used outside DRF), always use `Meta.fields` allowlist instead of `Meta.exclude` or `"__all__"`.
- DO NOT use `Meta.exclude` (denylist approach) or `ModelForms.Meta.fields = "__all__"`.
- Rate Limiting & Throttling
- Configure `DEFAULT_THROTTLE_CLASSES` to enable API rate limiting as a DoS defense layer.
- Prefer to enforce rate limiting at the gateway or WAF level; DRF throttling is a last-resort safeguard.
- Security Configuration
- Ensure `DEBUG` and `DEBUG_PROPAGATE_EXCEPTIONS` are set to `False` in production environments.
- Never hardcode secrets such as `SECRET_KEY`; inject them via environment variables or secrets managers.
- Disable all unused or dangerous HTTP methods (e.g., PUT, DELETE) at the API level.
- Validate, sanitize, and filter all incoming data rigorously.
- Set secure HTTP headers: `SECURE_CONTENT_TYPE_NOSNIFF = True`, `X_FRAME_OPTIONS = 'DENY'`, `SECURE_BROWSER_XSS_FILTER = True`.
- Implement Content Security Policy (CSP) using django-csp middleware to prevent XSS and clickjacking attacks.
- Prevent Injection Attacks
- Avoid raw SQL queries with user input; use ORM or parameterized queries exclusively.
- DO NOT add user input to dangerous methods (`raw()`, `extra()`, `cursor.execute()`).
- For YAML parsing, use safe loaders (`yaml.SafeLoader`); never parse YAML or pickle data from untrusted sources.
- DO NOT use `eval()`, `exec()`, or similar dynamic code execution functions on user input.
- Secret Management
- Never hardcode secrets such as `SECRET_KEY`; inject them via environment variables or secrets managers.
- DO NOT hardcode API keys, database passwords, or other sensitive credentials in source code.
- Input Validation
- Validate, sanitize, and filter all client-provided data rigorously.
- Use Django's built-in form validation or DRF serializers with proper validation methods.
- Logging Security
- Log authentication failures, authorization denials, and validation errors with sufficient context.
- DO NOT log sensitive data (passwords, tokens, PII) in application logs.
- Include stack traces, error messages, and user context in security-relevant log entries.
Summary:
Always enforce object-level permissions with `check_object_permissions()`, use explicit field allowlists in serializers, avoid dangerous functions with user input, never hardcode secrets, implement proper input validation, and ensure security-aware logging practices.
================================================
FILE: sources/owasp/codeguard-0-django-security.md
================================================
---
description: Django Security Best Practices
languages:
- c
- python
alwaysApply: false
---
## Django Security Guidelines
This rule advises on critical Django security practices to prevent common web vulnerabilities:
- General Security Configuration
- Never set `DEBUG = True` in production environments.
- Keep Django and dependencies up-to-date regularly.
- Use rate limiting packages like `django_ratelimit` or `django-axes` for brute-force protection.
- Authentication System
- Include `django.contrib.auth`, `django.contrib.contenttypes`, and `django.contrib.sessions` in `INSTALLED_APPS`.
- Use `@login_required` decorator to protect views requiring authentication.
- Configure `AUTH_PASSWORD_VALIDATORS` with appropriate validators for password policies.
- Use `make_password()` and `check_password()` functions for password hashing and verification.
- Secret Key Management
- Generate `SECRET_KEY` with at least 50 characters containing letters, digits, and symbols.
- Use `get_random_secret_key()` function for key generation.
- Store `SECRET_KEY` in environment variables, never hardcode in source.
- Rotate keys regularly and immediately upon exposure.
- Security Middleware Configuration
- Include `django.middleware.security.SecurityMiddleware` in `MIDDLEWARE` settings.
- Include `django.middleware.clickjacking.XFrameOptionsMiddleware` in `MIDDLEWARE` settings.
- Set `SECURE_CONTENT_TYPE_NOSNIFF = True` for MIME type protection.
- Configure `SECURE_HSTS_SECONDS` with positive integer for HTTPS enforcement.
- Set `X_FRAME_OPTIONS = 'DENY'` or `'SAMEORIGIN'` for clickjacking protection.
- Cookie Security
- Set `SESSION_COOKIE_SECURE = True` to send session cookies over HTTPS only.
- Set `CSRF_COOKIE_SECURE = True` to send CSRF cookies over HTTPS only.
- Use `secure=True` parameter when setting custom cookies with `HttpResponse.set_cookie()`.
- CSRF Protection
- Include `django.middleware.csrf.CsrfViewMiddleware` in `MIDDLEWARE` settings.
- Use `{% csrf_token %}` template tag in all forms.
- Extract CSRF token properly for AJAX calls.
- XSS Protection
- Use Django's built-in template system with automatic HTML escaping.
- Avoid `safe` filter and `mark_safe` function unless input is from trusted sources.
- Use `json_script` template filter for passing data to JavaScript.
- HTTPS Configuration
- Set `SECURE_SSL_REDIRECT = True` to redirect HTTP requests to HTTPS.
- Configure `SECURE_PROXY_SSL_HEADER` when behind proxy or load balancer.
- Admin Panel Security
- Change default admin URL from `/admin/` to custom path in `urls.py`.
Code Examples (from OWASP):
```python
# Authentication setup
INSTALLED_APPS = [
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
]
@login_required
def my_view(request):
# Your view logic
# Password validation
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
'OPTIONS': {
'min_length': 8,
}
},
]
# Secret key from environment
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')
# Cookie security
response.set_cookie('my_cookie', 'cookie_value', secure=True)
```
```html
```
Summary:
Configure Django securely by disabling debug mode in production, using proper authentication settings, securing secret keys, enabling security middleware, setting secure cookie attributes, implementing CSRF protection, preventing XSS, enforcing HTTPS, and securing admin access.
================================================
FILE: sources/owasp/codeguard-0-docker-security.md
================================================
---
description: Docker Security Best Practices
languages:
- docker
- yaml
alwaysApply: false
---
## Docker Security Guidelines
This rule advises on critical Docker container security practices to protect against common risks:
- Container User Security
- Always specify a non-root user in Dockerfiles using `USER` directive.
- Never run containers as root; use `docker run -u ` or Kubernetes `securityContext.runAsUser`.
- Avoid `USER root` or missing `USER` directives in Dockerfiles.
- Docker Daemon Socket Protection
- DO NOT expose `/var/run/docker.sock` to containers via volume mounts.
- DO NOT enable TCP Docker daemon socket (`-H tcp://0.0.0.0:XXX`) without TLS.
- Avoid `- "/var/run/docker.sock:/var/run/docker.sock"` in docker-compose files.
- Capability and Privilege Management
- Drop all capabilities (`--cap-drop all`) and add only required ones (`--cap-add`).
- DO NOT use `--privileged` flag in container configurations.
- Set `allowPrivilegeEscalation: false` in Kubernetes security contexts.
- Use `--security-opt=no-new-privileges` to prevent privilege escalation.
- Dockerfile Security Practices
- Pin base image versions (avoid `latest` tags in production).
- Use `COPY` instead of `ADD` when not extracting archives.
- DO NOT include secrets, passwords, or API keys in Dockerfiles.
- Avoid curl bashing in `RUN` directives; use package managers when possible.
- Include `HEALTHCHECK` instructions for container health monitoring.
- Resource and Filesystem Security
- Limit container resources (memory, CPU) in docker-compose or Kubernetes specs.
- Use read-only root filesystems (`--read-only` or `readOnlyRootFilesystem: true`).
- Mount volumes as read-only (`:ro`) when write access is not needed.
- Use `--tmpfs` for temporary writable storage instead of persistent volumes.
- Network and Runtime Security
- Avoid default bridge networking; define custom Docker networks.
- DO NOT share host network namespace (`--net=host`).
- DO NOT expose unnecessary ports in Dockerfiles or container configs.
- Enable default security profiles (seccomp, AppArmor, SELinux); do not disable them.
- Secret Management
- Use Docker Secrets or Kubernetes encrypted secrets for sensitive data.
- DO NOT embed secrets in environment variables or Dockerfile layers.
- Avoid hardcoded credentials in container configurations.
- Container Image Security
- Scan images for vulnerabilities before deployment.
- Use minimal base images (alpine, distroless) to reduce attack surface.
- Remove package managers and unnecessary tools from production images.
Summary:
Always run containers as non-root users, never expose Docker daemon socket, drop unnecessary capabilities, use secure Dockerfile practices, implement resource limits and read-only filesystems, configure proper networking, manage secrets securely, and scan images for vulnerabilities.
================================================
FILE: sources/owasp/codeguard-0-dom-based-xss-prevention.md
================================================
---
description: DOM-based XSS Prevention Best Practices
languages:
- c
- html
- javascript
- php
- typescript
- vlang
alwaysApply: false
---
## DOM-based XSS Prevention Security Rule
**RULE ENFORCEMENT:** This rule prevents DOM-based XSS vulnerabilities where untrusted data from user-controllable sources is inserted into DOM sinks without proper encoding or sanitization.
## Rule 1: DOM Sink Restrictions by Context
**YOU MUST secure DOM sinks** based on risk level:
### High-Risk HTML Sinks
```javascript
// VIOLATION: Direct assignment to HTML sinks
element.innerHTML = userInput; // DANGEROUS
element.outerHTML = userInput; // DANGEROUS
document.write(userInput); // DANGEROUS
// REQUIRED: Use safe alternatives
element.textContent = userInput; // SAFE
element.innerHTML = DOMPurify.sanitize(userInput); // SAFE
```
### Critical JavaScript Execution Sinks
```javascript
// VIOLATION: Code execution sinks
eval(userInput); // CRITICAL VULNERABILITY
new Function(userInput); // CRITICAL VULNERABILITY
setTimeout(userInput, 100); // CRITICAL VULNERABILITY
// REQUIRED: Safe alternatives
setTimeout(() => processData(userInput), 100); // SAFE
JSON.parse(userInput); // SAFE for JSON
```
### Medium-Risk URL/Event Sinks
```javascript
// VIOLATION: Unvalidated assignments
location.href = userInput; // DANGEROUS
element.onclick = userInput; // DANGEROUS
// REQUIRED: Validate and use safe patterns
if (/^https?:\/\/trusted-domain\.com/.test(userInput)) {
location.href = encodeURI(userInput);
}
element.addEventListener('click', () => handleClick(userInput));
```
## Rule 2: Mandatory CSP and Trusted Types
**YOU MUST implement strict CSP:**
```http
Content-Security-Policy:
script-src 'self' 'nonce-{random}';
object-src 'none';
base-uri 'self';
require-trusted-types-for 'script';
```
**YOU MUST use Trusted Types:**
```javascript
const policy = trustedTypes.createPolicy('dom-xss-prevention', {
createHTML: (string) => DOMPurify.sanitize(string, {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'p', 'br'],
ALLOWED_ATTR: []
})
});
element.innerHTML = policy.createHTML(userInput);
```
## Rule 3: Server-Side Validation Requirements
**YOU MUST validate all user input server-side:**
```javascript
function validateInput(input, context) {
if (input.length > 1000) throw new Error('Input too long');
const patterns = {
html: /`
- `javascript:alert('XSS')`
- `">`
- `'; eval('alert(1)'); //`
================================================
FILE: sources/owasp/codeguard-0-dom-clobbering-prevention.md
================================================
---
description: DOM Clobbering Prevention Best Practices
languages:
- c
- html
- javascript
- php
- typescript
- vlang
alwaysApply: false
---
## DOM Clobbering Prevention Security Rule
**RULE ENFORCEMENT:** This rule prevents DOM clobbering attacks where malicious HTML elements with `id` or `name` attributes override JavaScript variables and browser APIs, potentially leading to XSS and security bypasses.
## Rule 1: HTML Sanitization Requirements
**YOU MUST sanitize all user-provided HTML** using DOMPurify or Sanitizer API:
```javascript
// REQUIRED: DOMPurify configuration
const clean = DOMPurify.sanitize(userInput, {
SANITIZE_DOM: true, // Protects built-in APIs
SANITIZE_NAMED_PROPS: true, // MANDATORY: Protects custom variables
FORBID_ATTR: ['id', 'name'] // REQUIRED: Remove clobbering attributes
});
// ALTERNATIVE: Sanitizer API
const sanitizer = new Sanitizer({
blockAttributes: [{'name': 'id', elements: '*'}, {'name': 'name', elements: '*'}]
});
element.setHTML(userInput, {sanitizer});
```
**YOU ARE PROHIBITED FROM:**
* Using `innerHTML` with unsanitized user input
* Allowing `id` or `name` attributes in user-generated content
* Disabling `SANITIZE_NAMED_PROPS` in DOMPurify configuration
## Rule 2: Content Security Policy Requirements
**YOU MUST implement strict CSP** to prevent DOM clobbering exploitation:
```http
Content-Security-Policy:
script-src 'self' 'nonce-{random}';
object-src 'none';
base-uri 'self';
require-trusted-types-for 'script';
```
**YOU MUST use Trusted Types** for DOM manipulation:
```javascript
const policy = trustedTypes.createPolicy('dompurify', {
createHTML: (string) => DOMPurify.sanitize(string, {SANITIZE_NAMED_PROPS: true})
});
element.innerHTML = policy.createHTML(userInput);
```
## Rule 3: Variable Declaration Requirements
**YOU MUST use explicit variable declarations** to prevent global namespace pollution:
```javascript
"use strict"; // REQUIRED in all JavaScript files
const config = { isAdmin: false }; // REQUIRED: Explicit declarations
let userState = {}; // REQUIRED: Block-scoped variables
// PROHIBITED: Creates vulnerable globals
config = { isAdmin: false }; // WILL BE FLAGGED AS VIOLATION
```
**YOU ARE PROHIBITED FROM:**
* Storing sensitive data on `window` or `document` objects
* Using implicit global variables without declaration keywords
* Accessing user input on the left side of assignment expressions
## Rule 4: Object Validation Requirements
**YOU MUST validate object types** before accessing potentially clobbered properties:
```javascript
// REQUIRED: Type validation before use
function safePropertyAccess(obj, property) {
if (obj && typeof obj === 'object' && !(obj instanceof Element)) {
return obj[property];
}
throw new Error('Potential DOM clobbering detected');
}
// REQUIRED: Validate built-in APIs
if (typeof document.getElementById === 'function') {
const element = document.getElementById('myId');
}
```
## Rule 5: Dynamic Attribute Restrictions
**YOU MUST validate all dynamic HTML attributes:**
```javascript
function setElementAttribute(element, name, value) {
const forbidden = ['id', 'name', 'onclick', 'onload', 'onerror'];
if (forbidden.includes(name.toLowerCase())) {
throw new Error(`Attribute ${name} is prohibited for security`);
}
element.setAttribute(name, DOMPurify.sanitize(value, {ALLOWED_TAGS: []}));
}
```
**YOU ARE PROHIBITED FROM:**
* Setting `id` or `name` attributes from user input
* Using dynamic attribute assignment without validation
* Bypassing sanitization for `data-` or `aria-` attributes
## Rule 6: Framework Security Requirements
**React/Vue applications MUST use sanitized HTML rendering:**
```javascript
// REACT: Required safe HTML component
function SafeHtmlComponent({ userContent }) {
const clean = DOMPurify.sanitize(userContent, {
SANITIZE_NAMED_PROPS: true,
FORBID_ATTR: ['id', 'name']
});
return ;
}
// VUE: Required directive
Vue.directive('safe-html', {
update(el, binding) {
el.innerHTML = DOMPurify.sanitize(binding.value, {
SANITIZE_NAMED_PROPS: true,
FORBID_ATTR: ['id', 'name']
});
}
});
```
## Rule 7: Runtime Monitoring Requirements
**YOU MUST implement DOM clobbering detection:**
```javascript
// REQUIRED: Runtime monitoring
function detectClobbering() {
['config', 'api', 'user', 'admin'].forEach(global => {
if (window[global] instanceof Element) {
console.error(`SECURITY VIOLATION: DOM Clobbering detected on ${global}`);
securityLogger.warn('DOM_CLOBBERING_DETECTED', { variable: global });
}
});
}
setInterval(detectClobbering, 5000);
```
## Rule Violation Detection
**The following patterns will trigger security violations:**
```javascript
// VIOLATION: Implicit global creation
config = { sensitive: true };
// VIOLATION: Storing sensitive data on window
window.userRole = 'admin';
// VIOLATION: Unvalidated innerHTML usage
element.innerHTML = userInput;
// VIOLATION: Dynamic property access without validation
obj[userControlledProperty] = value;
// VIOLATION: Missing sanitization
document.body.appendChild(htmlFromUser);
```
## Mandatory Compliance Checks
The following checks MUST be performed:
✅ **DOMPurify imported and configured with `SANITIZE_NAMED_PROPS: true`**
✅ **No direct `innerHTML` usage without sanitization**
✅ **Strict mode enabled in all JavaScript files**
✅ **CSP headers implemented with `script-src 'self'`**
✅ **No `id` or `name` attributes in user content**
✅ **Runtime clobbering detection implemented**
✅ **Type validation before property access**
**NON-COMPLIANCE CONSEQUENCES:** Code that violates these rules creates DOM clobbering vulnerabilities that can lead to XSS attacks and privilege escalation.
**TEST PAYLOAD:** `` must be properly sanitized or blocked.
================================================
FILE: sources/owasp/codeguard-0-dotnet-security.md
================================================
---
description: DotNet Security Best Practices
languages:
- c
- javascript
- xml
alwaysApply: false
---
## .NET Security Guidelines
This rule advises on critical .NET security practices to prevent common web vulnerabilities:
- General Security Configuration
- Keep .NET Framework, .NET Core, and all NuGet packages up-to-date.
- Use Software Composition Analysis (SCA) tools in CI/CD pipelines.
- Subscribe to .NET Core and ASP.NET Core security announcements on GitHub.
- Access Control and Authorization
- Use `[Authorize]` attributes at controller or method level for all externally facing endpoints.
- Always validate user permissions server-side before resource access.
- Check roles using `User.Identity.IsInRole` in code when needed.
- Implement proper direct object reference validation to prevent IDOR attacks.
- Authentication and Session Management
- Use ASP.NET Core Identity with secure password policies and account lockout.
- Set cookies with `HttpOnly = true` and `requireSSL = true` in production.
- Reduce session timeout and disable sliding expiration for better security.
- Throttle login, registration, and password reset methods against brute force attacks.
- Cryptographic Security
- Never write custom cryptographic functions; use .NET's proven implementations.
- Use strong hashing algorithms: SHA512 for general hashing, PBKDF2 for passwords.
- Use AES-GCM for encryption with proper key management.
- Use Windows Data Protection API (DPAPI) for secure local storage.
- Enforce TLS 1.2+ for all network communications.
- Injection Prevention
- Use parameterized SQL queries or Entity Framework exclusively.
- Never concatenate user input into SQL commands or OS commands.
- Use allowlist validation on all user input with methods like `IPAddress.TryParse`.
- Escape LDAP special characters with backslash when needed.
- Security Misconfiguration
- Disable debug and tracing in production using web.config transforms.
- Force HTTPS redirects using `app.UseHttpsRedirection()` or Global.asax.
- Remove server version headers and implement secure HTTP headers.
- Never use default passwords or credentials.
- CSRF Protection
- Use anti-forgery tokens with `@Html.AntiForgeryToken()` in forms.
- Validate tokens with `[ValidateAntiForgeryToken]` on POST/PUT actions.
- Set `ViewStateUserKey = Session.SessionID` for Web Forms CSRF protection.
- Remove anti-forgery cookies on logout.
- Secure Headers Configuration
- Set `X-Frame-Options`, `X-Content-Type-Options`, `Content-Security-Policy` headers.
- Configure HSTS with `Strict-Transport-Security` header.
- Remove `X-Powered-By` and version disclosure headers.
- Logging and Monitoring
- Log authentication failures, access control violations with user context.
- Use ILogger framework for centralized logging.
- Never log sensitive data like passwords or tokens.
- Include stack traces and error context in security logs.
- Serialization Security
- Avoid `BinaryFormatter` which is dangerous for untrusted data.
- Use `System.Text.Json`, `XmlSerializer`, or `DataContractSerializer` safely.
- Never deserialize untrusted data without validation.
- Implement digital signature validation for serialized objects.
CSRF Protection Example (from OWASP):
```csharp
protected override OnInit(EventArgs e) {
base.OnInit(e);
ViewStateUserKey = Session.SessionID;
}
```
Secure Headers Configuration (from OWASP):
```xml
```
Summary:
Secure .NET applications by implementing proper authorization controls, using secure authentication and session management, applying strong cryptography, preventing injection attacks, configuring security headers, implementing CSRF protection, maintaining secure configurations, logging security events properly, and handling serialization safely.
================================================
FILE: sources/owasp/codeguard-0-error-handling.md
================================================
---
description: Error Handling Security Best Practices
languages:
- c
- java
- javascript
- python
- typescript
- xml
alwaysApply: false
---
## Error Handling Security Guidelines
This rule advises on secure error handling practices to prevent information leakage and ensure proper logging:
- General Error Handling Security
- Implement global error handlers to catch all unhandled exceptions.
- Return generic error messages without exposing stack traces, file paths, or version information.
- Log detailed error information securely on the server side for investigation.
- Use appropriate HTTP status codes: 4xx for client errors, 5xx for server errors.
- Production Environment Configuration
- Disable detailed error pages and debug information in production.
- Set `customErrors mode="RemoteOnly"` in web.config for ASP.NET applications.
- Disable development exception pages in ASP.NET Core production environments.
- Configure proper error page redirects to generic error handlers.
- Secure Error Logging
- Log exceptions with sufficient context (user ID, IP address, timestamp) for forensics.
- Never log sensitive data like passwords, tokens, or personal information in error logs.
- Use structured logging for better analysis and monitoring.
- Implement log rotation and secure storage for error logs.
- Error Response Security
- Return consistent error response formats using standards like RFC 7807.
- Add security headers to error responses to prevent XSS and information disclosure.
- Ensure error response content is properly escaped to prevent injection attacks.
- Remove server version headers and technology stack information from error responses.
Code Examples (from OWASP):
Standard Java Web Application:
```xml
java.lang.Exception
/error.jsp
```
```java
<%@ page language="java" isErrorPage="true" contentType="application/json; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
String errorMessage = exception.getMessage();
//Log the exception via the content of the implicit variable named "exception"
//...
//We build a generic response with a JSON format because we are in a REST API app context
//We also add an HTTP response header to indicate to the client app that the response is an error
response.setHeader("X-ERROR", "true");
//Note that we're using an internal server error response
//In some cases it may be prudent to return 4xx error codes, when we have misbehaving clients
response.setStatus(500);
%>
{"message":"An error occur, please retry"}
```
Spring Boot Global Error Handler:
```java
@RestControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(value = {Exception.class})
public ProblemDetail handleGlobalError(RuntimeException exception, WebRequest request) {
//Log the exception via the content of the parameter named "exception"
//...
//Note that we're using an internal server error response
//In some cases it may be prudent to return 4xx error codes, if we have misbehaving clients
//By specification, the content-type can be "application/problem+json" or "application/problem+xml"
return ProblemDetail.forStatusAndDetail(HttpStatus.INTERNAL_SERVER_ERROR, "An error occur, please retry");
}
}
```
ASP.NET Core Error Controller:
```csharp
[Route("api/[controller]")]
[ApiController]
[AllowAnonymous]
public class ErrorController : ControllerBase
{
[HttpGet]
[HttpPost]
[HttpHead]
[HttpDelete]
[HttpPut]
[HttpOptions]
[HttpPatch]
public JsonResult Handle()
{
//Get the exception that has implied the call to this controller
Exception exception = HttpContext.Features.Get()?.Error;
//Log the exception via the content of the variable named "exception" if it is not NULL
//...
//We build a generic response with a JSON format because we are in a REST API app context
//We also add an HTTP response header to indicate to the client app that the response is an error
var responseBody = new Dictionary{ {
"message", "An error occur, please retry"
} };
JsonResult response = new JsonResult(responseBody);
//Note that we're using an internal server error response
//In some cases it may be prudent to return 4xx error codes, if we have misbehaving clients
response.StatusCode = (int)HttpStatusCode.InternalServerError;
Request.HttpContext.Response.Headers.Remove("X-ERROR");
Request.HttpContext.Response.Headers.Add("X-ERROR", "true");
return response;
}
}
```
ASP.NET Web.config Security Configuration:
```xml
```
Summary:
Implement centralized error handling with generic user messages while logging detailed error information securely. Disable debug information in production and ensure error responses don't leak sensitive system details.
================================================
FILE: sources/owasp/codeguard-0-file-upload.md
================================================
---
description: File Upload Security Best Practices
languages:
- c
- go
- java
- javascript
- php
- python
- ruby
- typescript
alwaysApply: false
---
## File Upload Security Guidelines
This rule advises on secure file upload practices to prevent malicious file attacks and protect system integrity:
- Extension Validation
- List allowed extensions only for business-critical functionality.
- Ensure input validation is applied before validating extensions.
- Avoid double extensions (e.g., `.jpg.php`) and null byte injection (e.g., `.php%00.jpg`).
- Use allowlist approach rather than denylist for file extensions.
- Validate extensions after decoding filename to prevent bypass attempts.
- Content Type and File Signature Validation
- Never trust client-supplied Content-Type headers as they can be spoofed.
- Validate file signatures (magic numbers) in conjunction with Content-Type checking.
- Implement allowlist approach for MIME types as a quick protection layer.
- Use file signature validation but not as a standalone security measure.
- Filename Security
- Generate random filenames (UUID/GUID) instead of using user-supplied names.
- If user filenames required, implement maximum length limits.
- Restrict characters to alphanumeric, hyphens, spaces, and periods only.
- Prevent leading periods (hidden files) and sequential periods (directory traversal).
- Avoid leading hyphens or spaces for safer shell script processing.
- File Content Validation
- For images, apply image rewriting techniques to destroy malicious content.
- For Microsoft documents, use Apache POI for validation.
- Avoid ZIP files due to numerous attack vectors.
- Implement manual file review in sandboxed environments when resources allow.
- Integrate antivirus scanning and Content Disarm & Reconstruct (CDR) for applicable file types.
- Storage Security
- Store files on different servers for complete segregation when possible.
- Store files outside webroot with administrative access only.
- If storing in webroot, set write-only permissions with proper access controls.
- Use application handlers that map IDs to filenames for public access.
- Consider database storage for specific use cases with DBA expertise.
- Access Control and Authentication
- Require user authentication before allowing file uploads.
- Implement proper authorization levels for file access and modification.
- Set filesystem permissions on principle of least privilege.
- Scan files before execution if execution permission is required.
- Upload and Download Limits
- Set proper file size limits for upload protection.
- Consider post-decompression size limits for compressed files.
- Implement request limits for download services to prevent DoS attacks.
- Use secure methods to calculate ZIP file sizes safely.
- Additional Security Measures
- Protect file upload endpoints from CSRF attacks.
- Keep all file processing libraries securely configured and updated.
- Implement logging and monitoring for upload activities.
- Provide user reporting mechanisms for illegal content.
- Use secure extraction methods for compressed files.
Summary:
Implement defense-in-depth for file uploads through multi-layered validation, secure storage practices, proper access controls, and comprehensive monitoring. Never rely on single validation methods and always generate safe filenames to prevent attacks.
================================================
FILE: sources/owasp/codeguard-0-forgot-password.md
================================================
---
description: Forgot Password Security Best Practices
languages:
- c
- go
- java
- javascript
- php
- python
- ruby
- typescript
alwaysApply: false
---
## Forgot Password Security Guidelines
This rule advises on secure password reset implementation to prevent user enumeration, token abuse, and unauthorized access:
- Password Reset Request Security
- Return consistent messages for both existent and non-existent accounts to prevent user enumeration.
- Ensure consistent response times by using asynchronous processing or identical code paths.
- Implement rate limiting per account and IP address to prevent flooding attacks.
- Apply input validation and SQL injection prevention to reset request forms.
- Use CSRF tokens to protect password reset forms and endpoints.
- Token Generation and Storage
- Generate tokens using cryptographically secure random number generators.
- Make tokens sufficiently long to protect against brute-force attacks (minimum 32 bytes).
- Store password reset tokens securely using hashing (same practices as password storage).
- Link tokens to individual users in the database with expiration times.
- Make tokens single-use and invalidate immediately after successful use.
- Password Reset Process Security
- Require users to confirm new passwords by entering twice.
- Enforce consistent password policy throughout the application.
- Store new passwords following secure password storage practices.
- Send confirmation emails without including the actual password.
- Never automatically log users in after password reset.
- Invalidate all existing user sessions after successful password reset.
- URL Token Implementation
- Generate secure tokens and attach to URL query strings for email delivery.
- Use hardcoded or validated trusted domains for reset URLs (avoid Host header injection).
- Enforce HTTPS for all password reset URLs.
- Add referrer policy with 'noreferrer' value to prevent referrer leakage.
- Implement rate limiting to prevent token brute-forcing attempts.
- PIN Implementation
- Generate PINs between 6-12 digits using cryptographically secure methods.
- Create limited sessions from PINs that only permit password reset operations.
- Format PINs with spaces for better user readability.
- Apply same security practices as tokens (single-use, expiration, secure storage).
- Security Questions Integration
- Use security questions only as additional layer, never as sole mechanism.
- Follow secure question selection practices from OWASP guidance.
- Validate security question answers using secure comparison methods.
- Logging and Monitoring (Code-Level)
- Log password reset attempts with user context but never log tokens or passwords.
- Implement structured logging for security monitoring integration.
- Include sufficient context for security analysis (IP, user agent, timestamp).
- Never log sensitive information in application logs.
- Account Lockout Prevention
- Never lock accounts in response to password reset requests.
- Implement alternative abuse prevention through rate limiting and monitoring.
- Separate password reset abuse protection from authentication lockout mechanisms.
Summary:
Implement secure password reset functionality through consistent response handling, cryptographically secure token generation and storage, CSRF protection, proper session management, and comprehensive logging while preventing user enumeration and account lockout attacks.
================================================
FILE: sources/owasp/codeguard-0-graphql.md
================================================
---
description: GraphQL Security Best Practices
languages:
- javascript
- typescript
alwaysApply: false
---
## GraphQL Security Guidelines
This rule advises on secure GraphQL API development to prevent injection, DoS, unauthorized access, and information leakage:
- Input Validation and Injection Prevention
- Use specific GraphQL data types (scalars, enums) for all input validation.
- Define custom GraphQL validators for complex validations and use custom scalars.
- Define schemas for mutation inputs with strict validation rules.
- Use allowlist approach for character validation (avoid denylists).
- Apply parameterized statements and safe APIs for database queries in resolvers.
- Use ORMs/ODMs properly to avoid ORM injection vulnerabilities.
- Gracefully reject invalid input without revealing internal API details.
- DoS Prevention and Query Limiting
- Implement query depth limiting using libraries like graphql-depth-limit (JavaScript) or MaxQueryDepthInstrumentation (Java).
- Add query complexity analysis using graphql-cost-analysis or MaxQueryComplexityInstrumentation.
- Enforce query amount limiting with libraries like graphql-input-number.
- Implement pagination to limit data returned in single responses.
- Add query timeouts at application level using custom instrumentation.
- Apply rate limiting per IP or user to prevent basic DoS attacks.
- Use server-side batching and caching (like Facebook's DataLoader) for efficiency.
- Access Control and Authorization
- Validate requester authorization for all data viewing and mutation operations.
- Implement proper object-level authorization to prevent IDOR/BOLA vulnerabilities.
- Enforce authorization checks on both edges and nodes in GraphQL schema.
- Use Interfaces and Unions to return different object properties based on permissions.
- Add access control validation in Query and Mutation resolvers with RBAC middleware.
- Check for unintended node/nodes fields that allow direct object access by ID.
- Implement field-level access controls for sensitive data.
- Batching Attack Prevention
- Limit the number of queries that can be batched and run simultaneously.
- Add object request rate limiting at code level to track instance requests.
- Prevent batching for sensitive objects (usernames, passwords, tokens, OTPs).
- Implement custom solutions to disable batching for critical operations.
- Monitor and log batching attempts for security analysis.
- Secure Configuration Management
- Disable GraphQL introspection in production environments using NoIntrospectionGraphqlFieldVisibility (Java) or validation rules (JavaScript).
- Disable GraphiQL and similar exploration tools in production.
- Configure error masking to prevent stack traces and debug information exposure.
- Set NODE_ENV to 'production' or use debug: false in Apollo Server configuration.
- Disable field suggestion hints when introspection is disabled.
- Authentication and Session Management
- Require authentication for all GraphQL endpoints (unless explicitly public).
- Implement proper session management with secure token validation.
- Use JWT or session-based authentication with proper validation in resolvers.
- Apply CSRF protection for GraphQL mutations when using cookie-based authentication.
- Validate authentication state before processing any queries or mutations.
Code Examples (from OWASP):
Disable Introspection - Java:
```java
GraphQLSchema schema = GraphQLSchema.newSchema()
.query(StarWarsSchema.queryType)
.fieldVisibility( NoIntrospectionGraphqlFieldVisibility.NO_INTROSPECTION_FIELD_VISIBILITY )
.build();
```
Disable Introspection & GraphiQL - JavaScript:
```javascript
app.use('/graphql', graphqlHTTP({
schema: MySessionAwareGraphQLSchema,
+ validationRules: [NoIntrospection]
graphiql: process.env.NODE_ENV === 'development',
}));
```
Query Depth Example:
```javascript
query evil { # Depth: 0
album(id: 42) { # Depth: 1
songs { # Depth: 2
album { # Depth: 3
songs { # Depth: 4
album {id: N} # Depth: N
}
}
}
}
}
```
Excessive Amount Request Example:
```javascript
query {
author(id: "abc") {
posts(first: 99999999) {
title
}
}
}
```
Batching Attack Example:
```javascript
[
{
query: < query 0 >,
variables: < variables for query 0 >,
},
{
query: < query 1 >,
variables: < variables for query 1 >,
},
{
query: < query n >
variables: < variables for query n >,
}
]
```
Summary:
Secure GraphQL APIs through comprehensive input validation, query limiting, proper access controls, batching attack prevention, secure configuration management, and robust authentication mechanisms while preventing common attack vectors like injection, DoS, and unauthorized data access.
================================================
FILE: sources/owasp/codeguard-0-html5-security.md
================================================
---
description: HTML5 Security Best Practices
languages:
- c
- go
- html
- java
- javascript
- php
- python
- ruby
- typescript
- xml
alwaysApply: false
---
## HTML5 Security Guidelines
This rule advises on secure HTML5 development practices to prevent vulnerabilities in modern web applications:
- Web Messaging Security
- Always specify exact target origin in postMessage calls, never use "*" wildcard.
- Verify event.origin strictly against trusted full domain names in message handlers.
- Avoid partial domain matching that could allow subdomain takeover attacks.
- Validate and sanitize all data received through postMessage before processing.
- Never use eval() or Function() constructor on message data.
- Use textContent instead of innerHTML when setting received message content.
- Treat all cross-origin message data as untrusted input requiring validation.
- Cross-Origin Resource Sharing (CORS) Security
- Restrict Access-Control-Allow-Origin to specific trusted origins, avoid "*" wildcard.
- Validate URLs passed to XMLHttpRequest.open to prevent open redirects.
- Implement proper CSRF protection even when using CORS (CORS doesn't prevent CSRF).
- Reject mixed content requests (HTTP requests from HTTPS origins).
- Don't rely solely on Origin header for access control as it can be spoofed outside browsers.
- Use preflight requests for non-simple requests and validate Access-Control headers.
- WebSocket Security
- Use only secure wss:// protocol, never unencrypted ws:// in production.
- Implement application-level authentication and authorization for WebSocket connections.
- Verify Origin header against allowlist during WebSocket handshake.
- Validate and parse all WebSocket messages safely using JSON.parse() with error handling.
- Implement connection limits and message size restrictions to prevent DoS attacks.
- Use JWT or similar tokens for WebSocket authentication with proper validation.
- Implement token invalidation and denylist mechanisms for revoked access.
- Client-Side Storage Security
- Never store sensitive data (passwords, tokens, API keys, PII) in localStorage or sessionStorage.
- Use sessionStorage instead of localStorage when persistence across browser sessions is not required.
- Validate and sanitize all data retrieved from client-side storage before use.
- Implement data encryption for sensitive information stored client-side when absolutely necessary.
- Avoid hosting multiple applications on same origin to prevent storage access conflicts.
- DOM Manipulation and Link Security
- Add rel="noopener noreferrer" attribute to all external links with target="_blank".
- Set window.opener = null when using window.open() for external URLs.
- Use iframe sandbox attribute with minimal permissions for untrusted content.
- Implement X-Frame-Options header alongside iframe sandbox for defense-in-depth.
- Avoid innerHTML with user-supplied content; use textContent, createElement, or trusted templating.
- When innerHTML must be used, sanitize content with DOMPurify or similar libraries.
- Input Field Security and CSRF Protection
- Use autocomplete="off" on sensitive input fields (passwords, credit cards, SSN).
- Add spellcheck="false", autocorrect="off", autocapitalize="off" on credential inputs.
- Implement CSRF tokens on all state-changing forms and AJAX requests.
- Use secure cookie attributes: HttpOnly, Secure, SameSite=Strict for session cookies.
- Validate CSRF tokens on server-side for all POST, PUT, DELETE requests.
- Secure Cookie Configuration
- Set HttpOnly flag on session cookies to prevent JavaScript access.
- Use Secure flag to ensure cookies are only sent over HTTPS connections.
- Implement SameSite=Strict or SameSite=Lax to prevent CSRF attacks.
- Use __Secure- or __Host- cookie prefixes for additional security.
- Set appropriate cookie expiration and path restrictions.
- Web Workers and Service Workers Security
- Validate all messages sent to and received from Web Workers.
- Never create Web Workers from user-supplied URLs or content.
- Implement proper error handling and timeout mechanisms for Worker communications.
- Use Content Security Policy to restrict Worker script sources.
- Validate Service Worker registration and update mechanisms.
- Geolocation and Device API Security
- Require explicit user permission before accessing Geolocation API.
- Validate geolocation data before sending to servers.
- Implement proper error handling for geolocation failures.
- Use HTTPS when transmitting location data to prevent interception.
- Offline Application Security
- Require user consent before caching application data offline.
- Validate integrity of cached resources to prevent cache poisoning.
- Use HTTPS for all manifest files and cached resources.
- Implement proper cache invalidation mechanisms for security updates.
Summary:
Implement comprehensive HTML5 security controls through proper origin validation, secure storage practices, CSRF protection, secure cookie configuration, safe DOM manipulation, and robust authentication mechanisms to prevent XSS, CSRF, clickjacking, and data leakage vulnerabilities.
================================================
FILE: sources/owasp/codeguard-0-http-headers.md
================================================
---
description: HTTP Security Headers Best Practices
languages:
- c
- go
- java
- javascript
- php
- python
- ruby
- typescript
- xml
alwaysApply: false
---
## HTTP Security Headers Guidelines
This rule enforces secure configuration of HTTP response headers to protect against common web vulnerabilities including XSS, Clickjacking, Information Disclosure, and MIME-type attacks.
### Required Security Headers
1. Content Security Policy (CSP)
- Must include default-src directive
- Must include script-src directive with appropriate restrictions
- Must include frame-ancestors directive for clickjacking protection
- Example: `Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; frame-ancestors 'none'`
2. Cookie Security
- All session/sensitive cookies must have Secure flag
- All session/sensitive cookies must have HttpOnly flag
- All cookies must have SameSite attribute (Strict or Lax)
- Example: `Set-Cookie: session=123; Secure; HttpOnly; SameSite=Strict`
3. Cross-Origin Isolation
- Must set Cross-Origin-Embedder-Policy (COEP)
- Must set Cross-Origin-Resource-Policy (CORP)
- Must set Cross-Origin-Opener-Policy (COOP)
- Examples:
```
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Resource-Policy: same-origin
Cross-Origin-Opener-Policy: same-origin
```
4. Transport Security
- Must set Strict-Transport-Security (HSTS)
- Must include appropriate max-age (minimum 1 year)
- Example: `Strict-Transport-Security: max-age=31536000; includeSubDomains`
5. Cache Control
- Must set appropriate Cache-Control for sensitive data
- Example: `Cache-Control: no-store, max-age=0`
6. Content Type Protection
- Must set X-Content-Type-Options
- Example: `X-Content-Type-Options: nosniff`
### Prohibited Headers
The following headers must not be present or must be removed:
- X-Powered-By
- Server (or must contain non-revealing value)
- X-AspNet-Version
- X-AspNetMvc-Version
### Required Header Combinations
Certain security features require multiple headers to work effectively:
1. Clickjacking Protection:
- Must use CSP frame-ancestors OR
- Must use X-Frame-Options: DENY
2. XSS Protection:
- Must use CSP with appropriate script-src
- Must not rely solely on X-XSS-Protection
3. CORS Security:
- Must not use Access-Control-Allow-Origin: *
- Must explicitly list allowed origins
### Implementation Examples
PHP:
```php
header("X-Frame-Options: DENY");
```
Apache (.htaccess):
```apache
Header always set X-Frame-Options "DENY"
```
IIS (Web.config):
```xml
...
...
```
HAProxy:
```
http-response set-header X-Frame-Options DENY
```
Nginx:
```nginx
add_header "X-Frame-Options" "DENY" always;
```
Express.js:
```javascript
const helmet = require('helmet');
const app = express();
// Sets "X-Frame-Options: SAMEORIGIN"
app.use(
helmet.frameguard({
action: "sameorigin",
})
);
```
### Testing Tools
Mozilla Observatory is an online tool which helps you to check your website's header status.
SmartScanner has a dedicated test profile for testing security of HTTP headers. Online tools usually test the homepage of the given address. But SmartScanner scans the whole website, ensuring all web pages have the right HTTP Headers in place.
================================================
FILE: sources/owasp/codeguard-0-http-strict-transport-security.md
================================================
---
description: HTTP Strict Transport Security Best Practices
languages:
- c
- go
- java
- javascript
- php
- python
- ruby
- typescript
alwaysApply: false
---
## HTTP Strict Transport Security Guidelines
This rule enforces secure configuration of HTTP Strict Transport Security (HSTS) headers to protect users by ensuring all communications occur over HTTPS.
### Introduction
HTTP Strict Transport Security (HSTS) is an opt-in security enhancement specified by a web application through a special response header. Once a supported browser receives this header, it prevents any communications from being sent over HTTP to the specified domain and instead sends all communications over HTTPS. It also prevents HTTPS click through prompts on browsers.
Critical Requirement: The Strict-Transport-Security header is only honored over HTTPS connections and is completely ignored when sent over HTTP, per RFC 6797.
### Threats Addressed
HSTS protects against:
- Man-in-the-middle attacks when users bookmark or manually type `http://example.com`
- Web applications inadvertently containing HTTP links or serving content over HTTP
- Man-in-the-middle attackers using invalid certificates (HSTS prevents users from accepting bad certificates)
### Required Configuration
1. Basic HSTS Header (testing phase):
```
Strict-Transport-Security: max-age=86400; includeSubDomains
```
2. Production HSTS Header (1 year minimum):
```
Strict-Transport-Security: max-age=31536000; includeSubDomains
```
3. Preload-Ready HSTS Header:
```
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
```
### Phased Rollout Requirements
1. Phase 1 - Testing (recommended first step):
- Use short max-age (600-86400 seconds) for initial testing
- Monitor for any HTTP content or functionality issues
2. Phase 2 - Production:
- Increase max-age to minimum 1 year (31536000 seconds)
- Add `includeSubDomains` only if all subdomains support HTTPS
3. Phase 3 - Preload (optional):
- Add `preload` directive only after thorough testing
- Submit domain to HSTS preload list at hstspreload.org
- Warning: Preload is effectively permanent and affects all subdomains
### Implementation Examples
Simple example using 1 year max-age (dangerous without includeSubDomains):
```
Strict-Transport-Security: max-age=31536000
```
Secure example with subdomain protection:
```
Strict-Transport-Security: max-age=31536000; includeSubDomains
```
Short max-age for initial rollout testing:
```
Strict-Transport-Security: max-age=86400; includeSubDomains
```
### Monitoring and Validation
Required post-deployment actions:
- Verify HSTS header presence in all HTTPS responses
- Monitor browser console for mixed content warnings
- Audit all internal links and redirects for HTTP references
- Test subdomain HTTPS availability before enabling includeSubDomains
- Use tools like Mozilla Observatory or Security Headers to validate configuration
### Browser Support
HSTS is supported by all modern browsers. The only notable exception is Opera Mini.
================================================
FILE: sources/owasp/codeguard-0-injection-prevention.md
================================================
---
description: Injection Prevention Best Practices
languages:
- c
- go
- java
- javascript
- php
- powershell
- python
- ruby
- shell
- sql
- typescript
alwaysApply: false
---
## Injection Prevention Guidelines
This rule provides clear, actionable guidance for preventing injection flaws across multiple languages and injection types. Injection flaws occur when untrusted data is sent to an interpreter as part of a command or query.
### Introduction
Injection attacks, especially SQL Injection, are unfortunately very common. Injection flaws occur when an application sends untrusted data to an interpreter. Injection flaws are very prevalent, particularly in legacy code, often found in SQL queries, LDAP queries, XPath queries, OS commands, program arguments, etc.
### SQL Injection Prevention
Defense Option 1: Prepared Statements (with Parameterized Queries)
Safe Java Prepared Statement Example:
```java
// This should REALLY be validated too
String custname = request.getParameter("customerName");
String query = "SELECT account_balance FROM user_data WHERE user_name = ?";
PreparedStatement pstmt = connection.prepareStatement( query );
pstmt.setString( 1, custname);
ResultSet results = pstmt.executeQuery( );
```
Defense Option 2: Stored Procedures
Safe Java Stored Procedure Example:
```java
// This should REALLY be validated
String custname = request.getParameter("customerName");
try {
CallableStatement cs = connection.prepareCall("{call sp_getAccountBalance(?)}");
cs.setString(1, custname);
ResultSet results = cs.executeQuery();
// Result set handling...
} catch (SQLException se) {
// Logging and error handling...
}
```
Defense Option 3: Allow-List Input Validation
Defense Option 4: Escaping All User-Supplied Input
### LDAP Injection Prevention
Escape all variables using the right LDAP encoding function
Safe Java for LDAP escaping Example:
```java
public String escapeDN (String name) {
//From RFC 2253 and the / character for JNDI
final char[] META_CHARS = {'+', '"', '<', '>', ';', '/'};
String escapedStr = new String(name);
//Backslash is both a Java and an LDAP escape character,
//so escape it first
escapedStr = escapedStr.replaceAll("\\\\\\\\","\\\\\\\\");
//Positional characters - see RFC 2253
escapedStr = escapedStr.replaceAll("\^#","\\\\\\\\#");
escapedStr = escapedStr.replaceAll("\^ | $","\\\\\\\\ ");
for (int i=0 ; i < META_CHARS.length ; i++) {
escapedStr = escapedStr.replaceAll("\\\\" +
META_CHARS[i],"\\\\\\\\" + META_CHARS[i]);
}
return escapedStr;
}
```
```java
public String escapeSearchFilter (String filter) {
//From RFC 2254
String escapedStr = new String(filter);
escapedStr = escapedStr.replaceAll("\\\\\\\\","\\\\\\\\5c");
escapedStr = escapedStr.replaceAll("\\\\\*","\\\\\\\\2a");
escapedStr = escapedStr.replaceAll("\\\\(","\\\\\\\\28");
escapedStr = escapedStr.replaceAll("\\\\)","\\\\\\\\29");
escapedStr = escapedStr.replaceAll("\\\\" +
Character.toString('\u0000'), "\\\\\\\\00");
return escapedStr;
}
```
### Operating System Commands
If it is considered unavoidable the call to a system command incorporated with user-supplied input, the following two layers of defense should be used:
1. Parameterization - If available, use structured mechanisms that automatically enforce the separation between data and command
2. Input validation - the values for commands and the relevant arguments should be both validated:
- Commands must be validated against a list of allowed commands
- Arguments should be validated using positive or allowlist input validation
- Allow-list Regular Expression - explicitly define a list of good characters allowed and maximum length. Ensure that metacharacters like `& | ; $ > < \` \ !` and whitespaces are not part of the Regular Expression
Example regular expression: `^[a-z0-9]{3,10}$`
Incorrect Usage:
```java
ProcessBuilder b = new ProcessBuilder("C:\DoStuff.exe -arg1 -arg2");
```
Correct Usage:
```java
ProcessBuilder pb = new ProcessBuilder("TrustedCmd", "TrustedArg1", "TrustedArg2");
Map env = pb.environment();
pb.directory(new File("TrustedDir"));
Process p = pb.start();
```
### Injection Prevention Rules
Rule #1 (Perform proper input validation)
- Perform proper input validation. Positive or allowlist input validation with appropriate canonicalization is recommended, but is not a complete defense as many applications require special characters in their input.
Rule #2 (Use a safe API)
- The preferred option is to use a safe API which avoids the use of the interpreter entirely or provides a parameterized interface. Be careful of APIs, such as stored procedures, that are parameterized, but can still introduce injection under the hood.
Rule #3 (Contextually escape user data)
- If a parameterized API is not available, you should carefully escape special characters using the specific escape syntax for that interpreter.
================================================
FILE: sources/owasp/codeguard-0-input-validation.md
================================================
---
description: Input Validation Security Best Practices
languages:
- c
- go
- java
- javascript
- php
- python
- ruby
- sql
- typescript
- xml
alwaysApply: false
---
## Input Validation Security Guidelines
This rule provides clear, actionable guidance for implementing robust input validation security functionality in applications.
### Introduction
Input validation ensures only properly formed data enters the workflow, preventing malformed data from persisting in the database and triggering malfunction of downstream components. Input validation should happen as early as possible in the data flow.
Data from all potentially untrusted sources should be subject to input validation, including Internet-facing web clients and backend feeds from suppliers, partners, vendors or regulators.
Input Validation should not be used as the primary method of preventing XSS, SQL Injection and other attacks but can significantly contribute to reducing their impact if implemented properly.
### Input Validation Strategies
- Syntactic validation: enforce correct syntax of structured fields (e.g. SSN, date, currency symbol)
- Semantic validation: enforce correctness of values in specific business context (e.g. start date before end date, price within expected range)
### Implementing Input Validation
- Data type validators available in web application frameworks (Django Validators, Apache Commons Validators)
- Validation against JSON Schema and XML Schema (XSD)
- Type conversion with strict exception handling (Integer.parseInt() in Java, int() in Python)
- Range checks for numerical parameters and length checks for strings
- Array of allowed values for small sets of string parameters
- Regular expressions covering the whole input string (^...$) avoiding "any character" wildcards
### Allowlist vs Denylist
Allowlist validation defines exactly what IS authorized; everything else is not authorized. For structured data (dates, SSNs, zip codes, emails), define strong validation patterns using regular expressions. For fixed options (dropdowns, radio buttons), input must match exactly one offered value.
### Validating Free-form Unicode Text
- Normalization: Ensure canonical encoding across all text
- Character category allowlisting: Use Unicode categories like "decimal digits" or "letters"
- Individual character allowlisting: Allow specific characters like apostrophe for names
### Regular Expressions (Regex)
Be aware of RegEx Denial of Service (ReDoS) attacks. Input validation should:
- Be applied to all input data
- Define allowed character sets
- Define minimum and maximum length (e.g. {1,25})
### Allow List Regular Expression Examples
U.S. Zip Code: `^\d{5}(-\d{4})?$`
Java Example:
```java
private static final Pattern zipPattern = Pattern.compile("^\d{5}(-\d{4})?$");
public void doPost(HttpServletRequest request, HttpServletResponse response) {
try {
String zipCode = request.getParameter("zip");
if (!zipPattern.matcher(zipCode).matches()) {
throw new YourValidationException("Improper zipcode format.");
}
} catch(YourValidationException e) {
response.sendError(response.SC_BAD_REQUEST, e.getMessage());
}
}
```
### Client-side vs Server-side Validation
Input validation must be implemented on the server-side before data processing, as client-side validation can be circumvented by attackers.
### File Upload Validation
Upload Verification:
- Validate filename uses expected extension type
- Enforce maximum file size limits
- Check ZIP files before extraction (target path, compression level, estimated size)
Upload Storage:
- Use server-generated random filenames
- Analyze uploaded files for malicious content
- Server defines file paths, not client
Beware of dangerous file types:
- crossdomain.xml / clientaccesspolicy.xml
- .htaccess and .htpasswd
- Web executable scripts: aspx, asp, css, swf, jsp, js, php, cgi
Image Upload:
- Use image rewriting libraries to verify and strip content
- Set extension based on detected content type
- Ensure content type is within defined image types
### Email Address Validation
Syntactic Validation:
- Contains two parts separated by @
- No dangerous characters (backticks, quotes, null bytes)
- Domain contains only letters, numbers, hyphens, periods
- Length limits: local part ≤ 63 chars, total ≤ 254 chars
Semantic Validation:
- Send verification email with secure token
- Token requirements: ≥32 chars, cryptographically random, single-use, time-limited
================================================
FILE: sources/owasp/codeguard-0-insecure-direct-object-reference-prevention.md
================================================
---
description: Insecure Direct Object Reference Prevention
languages:
- c
- go
- java
- javascript
- kotlin
- php
- python
- ruby
- swift
- typescript
alwaysApply: false
---
## Insecure Direct Object Reference Prevention Guidelines
This rule provides actionable guidance for preventing IDOR vulnerabilities by implementing proper access control checks around direct object references.
### Introduction
Insecure Direct Object Reference (IDOR) is a vulnerability that arises when attackers can access or modify objects by manipulating identifiers used in a web application's URLs or parameters. It occurs due to missing access control checks, which fail to verify whether a user should be allowed to access specific data.
### Examples
For instance, when a user accesses their profile, the application might generate a URL like this:
```
https://example.org/users/123
```
The 123 in the URL is a direct reference to the user's record in the database, often represented by the primary key. If an attacker changes this number to 124 and gains access to another user's information, the application is vulnerable to Insecure Direct Object Reference.
In some cases, the identifier may not be in the URL, but rather in the POST body:
```html
```
In this example, attackers can manipulate the "user_id" field to modify profiles of other users without authorization.
### Identifier Complexity
In some cases, using more complex identifiers like GUIDs can make it practically impossible for attackers to guess valid values. However, even with complex identifiers, access control checks are essential. If attackers obtain URLs for unauthorized objects, the application should still block their access attempts.
### Mitigation
To mitigate IDOR, implement access control checks for each object that users try to access. Web frameworks often provide ways to facilitate this. Additionally, use complex identifiers as a defense-in-depth measure, but remember that access control is crucial even with these identifiers.
Avoid exposing identifiers in URLs and POST bodies if possible. Instead, determine the currently authenticated user from session information. When using multi-step flows, pass identifiers in the session to prevent tampering.
When looking up objects based on primary keys, use datasets that users have access to. For example, in Ruby on Rails:
```ruby
// vulnerable, searches all projects
@project = Project.find(params[:id])
// secure, searches projects related to the current user
@project = @current_user.projects.find(params[:id])
```
Verify the user's permission every time an access attempt is made. Implement this structurally using the recommended approach for your web framework.
As an additional defense-in-depth measure, replace enumerable numeric identifiers with more complex, random identifiers. You can achieve this by adding a column with random strings in the database table and using those strings in the URLs instead of numeric primary keys. Another option is to use UUIDs or other long random values as primary keys. Avoid encrypting identifiers as it can be challenging to do so securely.
================================================
FILE: sources/owasp/codeguard-0-jaas.md
================================================
---
description: JAAS Security Best Practices
languages:
- c
- java
- xml
alwaysApply: false
---
## Introduction - What is JAAS authentication
The process of verifying the identity of a user or another system is authentication.
JAAS, as an authentication framework manages the authenticated user's identity and credentials from login to logout.
The JAAS authentication lifecycle:
1. Create `LoginContext`.
2. Read the configuration file for one or more `LoginModules` to initialize.
3. Call `LoginContext.initialize()` for each LoginModule to initialize.
4. Call `LoginContext.login()` for each LoginModule.
5. If login successful then call `LoginContext.commit()` else call `LoginContext.abort()`
## Configuration file
The JAAS configuration file contains a `LoginModule` stanza for each `LoginModule` available for logging on to the application.
A stanza from a JAAS configuration file:
```text
Branches
{
USNavy.AppLoginModule required
debug=true
succeeded=true;
}
```
Note the placement of the semicolons, terminating both `LoginModule` entries and stanzas.
The word required indicates the `LoginContext`'s `login()` method must be successful when logging in the user. The `LoginModule`-specific values `debug` and `succeeded` are passed to the `LoginModule`.
They are defined by the `LoginModule` and their usage is managed inside the `LoginModule`. Note, Options are Configured using key-value pairing such as `debug="true"` and the key and value should be separated by a `=` sign.
## Main.java (The client)
- Execution syntax:
```text
Java –Djava.security.auth.login.config==packageName/packageName.config
packageName.Main Stanza1
Where:
packageName is the directory containing the config file.
packageName.config specifies the config file in the Java package, packageName.
packageName.Main specifies Main.java in the Java package, packageName.
Stanza1 is the name of the stanza Main() should read from the config file.
```
- When executed, the 1st command-line argument is the stanza from the config file. The Stanza names the `LoginModule` to be used. The 2nd argument is the `CallbackHandler`.
- Create a new `LoginContext` with the arguments passed to `Main.java`.
- `loginContext = new LoginContext (args[0], new AppCallbackHandler());`
- Call the LoginContext.Login Module:
- `loginContext.login();`
- The value in succeeded Option is returned from `loginContext.login()`.
- If the login was successful, a subject was created.
## LoginModule.java
A `LoginModule` must have the following authentication methods:
- `initialize()`
- `login()`
- `commit()`
- `abort()`
- `logout()`
### initialize()
In `Main()`, after the `LoginContext` reads the correct stanza from the config file, the `LoginContext` instantiates the `LoginModule` specified in the stanza.
- `initialize()` methods signature:
- `Public void initialize (Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options)`
- The arguments above should be saved as follows:
- `this.subject = subject;`
- `this.callbackHandler = callbackHandler;`
- `this.sharedState = sharedState;`
- `this.options = options;`
- What the `initialize()` method does:
- Builds a subject object of the `Subject` class contingent on a successful `login()`.
- Sets the `CallbackHandler` which interacts with the user to gather login information.
- If a `LoginContext` specifies 2 or more LoginModules, which is legal, they can share information via a `sharedState` map.
- Saves state information such as debug and succeeded in an options Map.
### login()
Captures user supplied login information. The code snippet below declares an array of two callback objects which, when passed to the `callbackHandler.handle` method in the `callbackHandler.java` program, will be loaded with a username and password provided interactively by the user:
```java
NameCallback nameCB = new NameCallback("Username");
PasswordCallback passwordCB = new PasswordCallback ("Password", false);
Callback[] callbacks = new Callback[] { nameCB, passwordCB };
callbackHandler.handle (callbacks);
```
- Authenticates the user
- Retrieves the user supplied information from the callback objects:
- `String ID = nameCallback.getName ();`
- `char[] tempPW = passwordCallback.getPassword ();`
- Compare `name` and `tempPW` to values stored in a repository such as LDAP.
- Set the value of the variable succeeded and return to `Main()`.
### commit()
Once the users credentials are successfully verified during `login()`, the JAAS authentication framework associates the credentials, as needed, with the subject.
There are two types of credentials, **Public** and **Private**:
- Public credentials include public keys.
- Private credentials include passwords and public keys.
Principals (i.e. Identities the subject has other than their login name) such as employee number or membership ID in a user group are added to the subject.
Below, is an example `commit()` method where first, for each group the authenticated user has membership in, the group name is added as a principal to the subject. The subject's username is then added to their public credentials.
Code snippet setting then adding any principals and a public credentials to a subject:
```java
public boolean commit() {
If (userAuthenticated) {
Set groups = UserService.findGroups (username);
for (Iterator itr = groups.iterator (); itr.hasNext (); {
String groupName = (String) itr.next ();
UserGroupPrincipal group = new UserGroupPrincipal (GroupName);
subject.getPrincipals ().add (group);
}
UsernameCredential cred = new UsernameCredential (username);
subject.getPublicCredentials().add (cred);
}
}
```
### abort()
The `abort()` method is called when authentication doesn't succeed. Before the `abort()` method exits the `LoginModule`, care should be taken to reset state including the username and password input fields.
### logout()
The release of the users principals and credentials when `LoginContext.logout` is called:
```java
public boolean logout() {
if (!subject.isReadOnly()) {
Set principals = subject.getPrincipals(UserGroupPrincipal.class);
subject.getPrincipals().removeAll(principals);
Set creds = subject.getPublicCredentials(UsernameCredential.class);
subject.getPublicCredentials().removeAll(creds);
return true;
} else {
return false;
}
}
```
## CallbackHandler.java
The `callbackHandler` is in a source (`.java`) file separate from any single `LoginModule` so that it can service a multitude of LoginModules with differing callback objects:
- Creates instance of the `CallbackHandler` class and has only one method, `handle()`.
- A `CallbackHandler` servicing a LoginModule requiring username & password to login:
```java
public void handle(Callback[] callbacks) {
for (int i = 0; i < callbacks.length; i++) {
Callback callback = callbacks[i];
if (callback instanceof NameCallback) {
NameCallback nameCallBack = (NameCallback) callback;
nameCallBack.setName(username);
} else if (callback instanceof PasswordCallback) {
PasswordCallback passwordCallBack = (PasswordCallback) callback;
passwordCallBack.setPassword(password.toCharArray());
}
}
}
```
================================================
FILE: sources/owasp/codeguard-0-java-security.md
================================================
---
description: Java Security Best Practices
languages:
- c
- java
- javascript
- typescript
- xml
- yaml
alwaysApply: false
---
## Java Security Guidelines
Key security practices for secure Java application development.
### SQL Injection Prevention
Use parameterized queries to prevent SQL injection:
```java
// Safe - PreparedStatement with parameters
String query = "select * from color where friendly_name = ?";
try (PreparedStatement pStatement = con.prepareStatement(query)) {
pStatement.setString(1, userInput);
try (ResultSet rSet = pStatement.executeQuery()) {
// Process results
}
}
```
### JPA Query Security
Use parameterized JPA queries:
```java
// Safe - Named parameters
String queryPrototype = "select c from Color c where c.friendlyName = :colorName";
Query queryObject = entityManager.createQuery(queryPrototype);
Color c = (Color) queryObject.setParameter("colorName", userInput).getSingleResult();
```
### XSS Prevention
Apply input validation and output encoding:
```java
// Input validation with allowlist
if (!Pattern.matches("[a-zA-Z0-9\\s\\-]{1,50}", userInput)) {
return false;
}
// Output sanitization
PolicyFactory policy = new HtmlPolicyBuilder().allowElements("p", "strong").toFactory();
String safeOutput = policy.sanitize(outputToUser);
safeOutput = Encode.forHtml(safeOutput);
```
### Secure Logging
Use parameterized logging to prevent log injection:
```java
// Safe - parameterized logging
logger.warn("Login failed for user {}.", username);
// Avoid - string concatenation
// logger.warn("Login failed for user " + username);
```
### Cryptography Best Practices
Use trusted cryptographic libraries and secure algorithms:
```java
// Use AES-GCM with proper nonce management
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, nonce);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, gcmParameterSpec);
// Generate secure random nonces
byte[] nonce = new byte[12];
SecureRandom.getInstanceStrong().nextBytes(nonce);
```
### Key Security Requirements
- Never hardcode cryptographic keys in source code
- Use Google Tink or similar trusted crypto libraries when possible
- Avoid writing custom cryptographic implementations
- Implement proper key rotation and management
- Keep all dependencies updated with security patches
================================================
FILE: sources/owasp/codeguard-0-json-web-token-for-java.md
================================================
---
description: JSON Web Token Security for Java
languages:
- c
- java
- javascript
- typescript
- xml
- yaml
alwaysApply: false
---
## JSON Web Token Security for Java
Key security practices for implementing JWT in Java applications.
### Algorithm Security
Always specify the expected algorithm explicitly:
```java
// Prevent 'none' algorithm attack
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(keyHMAC)).build();
DecodedJWT decodedToken = verifier.verify(token);
```
### Token Sidejacking Prevention
Code to create the token after successful authentication.
``` java
// HMAC key - Block serialization and storage as String in JVM memory
private transient byte[] keyHMAC = ...;
// Random data generator
private SecureRandom secureRandom = new SecureRandom();
...
//Generate a random string that will constitute the fingerprint for this user
byte[] randomFgp = new byte[50];
secureRandom.nextBytes(randomFgp);
String userFingerprint = DatatypeConverter.printHexBinary(randomFgp);
//Add the fingerprint in a hardened cookie - Add cookie manually because
//SameSite attribute is not supported by javax.servlet.http.Cookie class
String fingerprintCookie = "__Secure-Fgp=" + userFingerprint
+ "; SameSite=Strict; HttpOnly; Secure";
response.addHeader("Set-Cookie", fingerprintCookie);
//Compute a SHA256 hash of the fingerprint in order to store the
//fingerprint hash (instead of the raw value) in the token
//to prevent an XSS to be able to read the fingerprint and
//set the expected cookie itself
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] userFingerprintDigest = digest.digest(userFingerprint.getBytes("utf-8"));
String userFingerprintHash = DatatypeConverter.printHexBinary(userFingerprintDigest);
//Create the token with a validity of 15 minutes and client context (fingerprint) information
Calendar c = Calendar.getInstance();
Date now = c.getTime();
c.add(Calendar.MINUTE, 15);
Date expirationDate = c.getTime();
Map headerClaims = new HashMap<>();
headerClaims.put("typ", "JWT");
String token = JWT.create().withSubject(login)
.withExpiresAt(expirationDate)
.withIssuer(this.issuerID)
.withIssuedAt(now)
.withNotBefore(now)
.withClaim("userFingerprint", userFingerprintHash)
.withHeader(headerClaims)
.sign(Algorithm.HMAC256(this.keyHMAC));
```
Code to validate the token.
``` java
// HMAC key - Block serialization and storage as String in JVM memory
private transient byte[] keyHMAC = ...;
...
//Retrieve the user fingerprint from the dedicated cookie
String userFingerprint = null;
if (request.getCookies() != null && request.getCookies().length > 0) {
List cookies = Arrays.stream(request.getCookies()).collect(Collectors.toList());
Optional cookie = cookies.stream().filter(c -> "__Secure-Fgp"
.equals(c.getName())).findFirst();
if (cookie.isPresent()) {
userFingerprint = cookie.get().getValue();
}
}
//Compute a SHA256 hash of the received fingerprint in cookie in order to compare
//it to the fingerprint hash stored in the token
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] userFingerprintDigest = digest.digest(userFingerprint.getBytes("utf-8"));
String userFingerprintHash = DatatypeConverter.printHexBinary(userFingerprintDigest);
//Create a verification context for the token
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(keyHMAC))
.withIssuer(issuerID)
.withClaim("userFingerprint", userFingerprintHash)
.build();
//Verify the token, if the verification fail then an exception is thrown
DecodedJWT decodedToken = verifier.verify(token);
```
### Token Revocation
Implement token blacklist for logout functionality:
Code in charge of adding a token to the denylist and checking if a token is revoked.
``` java
/**
* Handle the revocation of the token (logout).
* Use a DB in order to allow multiple instances to check for revoked token
* and allow cleanup at centralized DB level.
*/
public class TokenRevoker {
/** DB Connection */
@Resource("jdbc/storeDS")
private DataSource storeDS;
/**
* Verify if a digest encoded in HEX of the ciphered token is present
* in the revocation table
*
* @param jwtInHex Token encoded in HEX
* @return Presence flag
* @throws Exception If any issue occur during communication with DB
*/
public boolean isTokenRevoked(String jwtInHex) throws Exception {
boolean tokenIsPresent = false;
if (jwtInHex != null && !jwtInHex.trim().isEmpty()) {
//Decode the ciphered token
byte[] cipheredToken = DatatypeConverter.parseHexBinary(jwtInHex);
//Compute a SHA256 of the ciphered token
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] cipheredTokenDigest = digest.digest(cipheredToken);
String jwtTokenDigestInHex = DatatypeConverter.printHexBinary(cipheredTokenDigest);
//Search token digest in HEX in DB
try (Connection con = this.storeDS.getConnection()) {
String query = "select jwt_token_digest from revoked_token where jwt_token_digest = ?";
try (PreparedStatement pStatement = con.prepareStatement(query)) {
pStatement.setString(1, jwtTokenDigestInHex);
try (ResultSet rSet = pStatement.executeQuery()) {
tokenIsPresent = rSet.next();
}
}
}
}
return tokenIsPresent;
}
### Secure Client Storage
Store tokens in sessionStorage with fingerprint binding:
```javascript
// Store in sessionStorage, not localStorage
sessionStorage.setItem("token", data.token);
// Send as Bearer token
xhr.setRequestHeader("Authorization", "bearer " + token);
```
### Strong Secrets
Use strong HMAC secrets or RSA keys:
- HMAC secrets: minimum 64 characters, cryptographically random
- Prefer RSA or ECDSA over HMAC for better security
- Never hardcode secrets in source code
================================================
FILE: sources/owasp/codeguard-0-key-management.md
================================================
---
description: Cryptographic Key Management Security
languages:
- c
- go
- java
- javascript
- kotlin
- python
- ruby
- swift
- typescript
alwaysApply: false
---
## Key Management Security Guidelines
Essential practices for secure cryptographic key management in applications.
### Key Generation
Cryptographic keys shall be generated within cryptographic module with at least FIPS 140-2 compliance. Any random value required by the key-generating module shall be generated within that module using a Random Bit Generator implemented within the cryptographic module.
Hardware cryptographic modules are preferred over software cryptographic modules for protection.
### Key Storage
- Keys must be protected on both volatile and persistent memory, ideally processed within secure cryptographic modules
- Keys should never be stored in plaintext format
- Ensure all keys are stored in a cryptographic vault, such as a hardware security module (HSM) or isolated cryptographic service
- When storing keys in offline devices/databases, encrypt the keys using Key Encryption Keys (KEKs) prior to export
- KEK length and algorithm should be equivalent to or greater in strength than the keys being protected
- Ensure that standard application level code never reads or uses cryptographic keys directly
### Key Usage and Separation
According to NIST, in general, a single key should be used for only one purpose (e.g., encryption, authentication, key wrapping, random number generation, or digital signatures).
Reasons for key separation:
- The use of the same key for two different cryptographic processes may weaken the security provided
- Limiting the use of a key limits the damage that could be done if the key is compromised
- Some uses of keys interfere with each other
### Memory Management
Keys stored in memory for a long time can become "burned in". This can be mitigated by splitting the key into components that are frequently updated.
Plan for the recovery from possible corruption of the memory media necessary for key or certificate generation, registration, and distribution systems.
### Key Backup and Recovery
Data that has been encrypted with lost cryptographic keys will never be recovered. Therefore, it is essential that applications incorporate a secure key backup capability.
When backing up keys, ensure that the database used to store the keys is encrypted using at least a FIPS 140-2 validated module.
Never escrow keys used for performing digital signatures, but consider the need to escrow keys that support encryption.
### Trust Store Security
- Design controls to secure the trust store against injection of third-party root certificates
- Implement integrity controls on objects stored in the trust store
- Do not allow for export of keys held within the trust store without authentication and authorization
- Setup strict policies and procedures for exporting key material
- Implement a secure process for updating the trust store
### Key Security Requirements
- Generate keys only in FIPS 140-2 validated modules or HSMs
- Use NIST-approved algorithms with appropriate key lengths
- Never reuse keys for different cryptographic purposes
- Implement key rotation and lifecycle management
- Use ephemeral keys for Perfect Forward Secrecy
- Monitor and audit all key access operations
- Use only reputable crypto libraries that are well maintained and validated by third-party organizations
================================================
FILE: sources/owasp/codeguard-0-kubernetes-security.md
================================================
---
description: Kubernetes Security Best Practices
languages:
- javascript
- shell
- yaml
alwaysApply: false
---
## Kubernetes Security Guidelines
Essential security practices for secure Kubernetes cluster deployment and management.
### Host and Component Security
Keep Kubernetes components updated to the latest stable version. The Kubernetes project maintains release branches for the most recent three minor releases with security fixes.
Secure critical components:
- Restrict access to etcd with mutual TLS authentication and firewall isolation
- Use strong credentials between API servers and etcd
- Control network access to sensitive ports (6443 for API server, 2379-2380 for etcd)
- Enable Kubelet authentication and authorization to prevent unauthenticated access
### Build Phase Security
Use approved, scanned container images from trusted registries:
- Store approved images in private registries
- Integrate vulnerability scanning into CI pipeline to block vulnerable images
- Use minimal base images (distroless when possible) to reduce attack surface
- Remove shells and package managers from runtime containers
### Deploy Phase Security
#### Pod Security Configuration
Apply security context to control pod security parameters:
```yaml
apiVersion: v1
kind: Pod
metadata:
name: hello-world
spec:
containers:
# specification of the pod's containers
# ...
# Security Context
securityContext:
readOnlyRootFilesystem: true
runAsNonRoot: true
```
#### Pod Security Standards
Use Pod Security Admission Controller with namespace-level enforcement:
```yaml
apiVersion: v1
kind: Namespace
metadata:
name: policy-test
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
```
Three security profiles available:
- **Privileged**: Unrestricted (system workloads only)
- **Baseline**: Minimally restrictive, prevents known privilege escalations
- **Restricted**: Most restrictive, enforces current pod hardening practices
#### Network Security
Implement network policies to control pod-to-pod communication:
```json
POST /apis/net.alpha.kubernetes.io/v1alpha1/namespaces/tenant-a/networkpolicys
{
"kind": "NetworkPolicy",
"metadata": {
"name": "pol1"
},
"spec": {
"allowIncoming": {
"from": [{
"pods": { "segment": "frontend" }
}],
"toPorts": [{
"port": 80,
"protocol": "TCP"
}]
},
"podSelector": {
"segment": "backend"
}
}
}
```
#### Resource Management
Define resource quotas to prevent DoS attacks:
```yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-resources
spec:
hard:
pods: "4"
requests.cpu: "1"
requests.memory: 1Gi
limits.cpu: "2"
limits.memory: 2Gi
```
### Secrets Management
- Mount secrets as read-only volumes rather than environment variables
- Store secrets separately from images and pods
- Enable encryption at rest for Secret resources in etcd
- Consider external secrets managers for multi-cluster environments
### Runtime Phase Security
#### Monitoring and Detection
Monitor container behavior for security anomalies:
- Shell execution inside containers
- Sensitive file access (e.g., /etc/shadow)
- Unexpected network connections
- Process activity deviations between replicas
#### Audit Logging
Enable Kubernetes audit logging to track API requests:
```json
{
"kind":"Event",
"apiVersion":"audit.k8s.io/v1beta1",
"metadata":{ "creationTimestamp":"2019-08-22T12:00:00Z" },
"level":"Metadata",
"timestamp":"2019-08-22T12:00:00Z",
"auditID":"23bc44ds-2452-242g-fsf2-4242fe3ggfes",
"stage":"RequestReceived",
"requestURI":"/api/v1/namespaces/default/persistentvolumeclaims",
"verb":"list",
"user": {
"username":"user@example.org",
"groups":[ "system:authenticated" ]
},
"sourceIPs":[ "172.12.56.1" ]
}
```
### Access Control
- Implement RBAC with least privilege principles
- Use external authentication (OIDC) with multi-factor authentication
- Avoid built-in authentication methods for production clusters
- Secure the Kubernetes Dashboard with authenticating reverse proxy
### Key Security Requirements
- Always run the latest stable Kubernetes version
- Use namespaces to isolate workloads
- Apply security contexts to prevent privileged container execution
- Implement network policies for traffic segmentation
- Enable comprehensive audit logging and monitoring
- Rotate credentials frequently and revoke bootstrap tokens promptly
- Use admission controllers to enforce security policies
================================================
FILE: sources/owasp/codeguard-0-laravel.md
================================================
---
description: Laravel Security Best Practices
languages:
- c
- javascript
- php
- typescript
- yaml
alwaysApply: false
---
## Laravel Security Guidelines
Essential security practices for building secure Laravel applications.
### Basic Configuration
Disable debug mode in production and generate application key:
```ini
APP_DEBUG=false
```
```bash
php artisan key:generate
```
Set secure file permissions: directories `775`, files `664`, executables `775`.
### Cookie Security and Session Management
Enable cookie encryption middleware in `App\Http\Kernel`:
```php
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
...
],
...
];
```
Configure secure session settings in `config/session.php`:
```php
'http_only' => true,
'domain' => null,
'same_site' => 'lax',
'secure' => null,
'lifetime' => 15,
```
### Mass Assignment Protection
Protect against mass assignment vulnerabilities:
```php
// VULNERABLE: Allows modification of any field
Route::any('/profile', function (Request $request) {
$request->user()->forceFill($request->all())->save();
return response()->json(compact('user'));
})->middleware('auth');
```
Use `$request->only()` or `$request->validated()` instead of `$request->all()`.
### SQL Injection Prevention
Use Eloquent ORM parameterized queries by default. For raw queries, always use bindings:
```php
// VULNERABLE: No SQL bindings
User::whereRaw('email = "'.$request->input('email').'"')->get();
// SAFE: Using SQL bindings
User::whereRaw('email = ?', [$request->input('email')])->get();
// SAFE: Named bindings
User::whereRaw('email = :email', ['email' => $request->input('email')])->get();
```
Validate column names to prevent column name injection:
```php
$request->validate(['sortBy' => 'in:price,updated_at']);
User::query()->orderBy($request->validated()['sortBy'])->get();
```
### XSS Prevention
Use Blade's automatic escaping for all untrusted data:
```blade
{{-- SAFE: Automatically escaped --}}
{{ request()->input('somedata') }}
{{-- VULNERABLE: Unescaped data --}}
{!! request()->input('somedata') !!}
```
### File Upload Security
Always validate file type and size:
```php
$request->validate([
'photo' => 'file|size:100|mimes:jpg,bmp,png'
]);
```
Sanitize filenames to prevent path traversal:
```php
Route::post('/upload', function (Request $request) {
$request->file('file')->storeAs(auth()->id(), basename($request->input('filename')));
return back();
});
```
### Path Traversal Prevention
Use `basename()` to strip directory information:
```php
Route::get('/download', function(Request $request) {
return response()->download(storage_path('content/').basename($request->input('filename')));
});
```
### CSRF Protection
Enable CSRF middleware and use tokens in forms:
```php
protected $middlewareGroups = [
'web' => [
...
\App\Http\Middleware\VerifyCsrfToken::class,
...
],
];
```
```html
```
### Command Injection Prevention
Escape shell commands with user input:
```php
public function verifyDomain(Request $request)
{
exec('whois '.$request->input('domain'));
}
```
Use `escapeshellcmd` and `escapeshellarg` for proper escaping.
### Rate Limiting
Apply throttling to protect against abuse:
```php
Route::get('/profile', function () {
return 'User profile';
})->middleware('throttle:10,1'); // 10 requests per minute
// Custom rate limiter
RateLimiter::for('custom-limit', function ($request) {
return Limit::perMinute(5)->by($request->user()?->id ?: $request->ip());
});
```
### Other Injection Prevention
Avoid dangerous functions with untrusted input:
```php
unserialize($request->input('data'));
eval($request->input('data'));
extract($request->all());
```
### Security Auditing
Use Enlightn Security Checker to scan for vulnerabilities and keep dependencies updated.
================================================
FILE: sources/owasp/codeguard-0-ldap-injection-prevention.md
================================================
---
description: LDAP Injection Prevention
languages:
- c
- go
- java
- javascript
- php
- python
- ruby
- typescript
- xml
- yaml
alwaysApply: false
---
## LDAP Injection Prevention Guidelines
Essential practices for preventing LDAP injection vulnerabilities in applications that use directory services.
### Understanding LDAP Injection
LDAP injection occurs when untrusted user input is improperly incorporated into LDAP queries, potentially allowing attackers to bypass authentication, access unauthorized data, or modify directory information.
Two main components vulnerable to injection:
- **Distinguished Names (DNs)**: Unique identifiers like `cn=Richard Feynman, ou=Physics Department, dc=Caltech, dc=edu`
- **Search Filters**: Query criteria using boolean logic in Polish notation
### Primary Defense: Proper Escaping
#### Distinguished Name Escaping
Characters that must be escaped in DNs: `\ # + < > , ; " =` and leading or trailing spaces.
Characters allowed in DNs (no escaping needed): `* ( ) . & - _ [ ] ` ~ | @ $ % ^ ? : { } ! '`
#### Search Filter Escaping
Characters that must be escaped in search filters: `* ( ) \ NUL`
### Safe Java Example
The original OWASP document provides this allowlist validation approach:
```java
// String userSN = "Sherlock Holmes"; // Valid
// String userPassword = "secret2"; // Valid
// ... beginning of LDAPInjection.searchRecord()...
sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
String base = "dc=example,dc=com";
if (!userSN.matches("[\\w\\s]*") || !userPassword.matches("[\\w]*")) {
throw new IllegalArgumentException("Invalid input");
}
String filter = "(&(sn = " + userSN + ")(userPassword=" + userPassword + "))";
// ... remainder of LDAPInjection.searchRecord()...
```
### Safe .NET Encoding
Use .NET AntiXSS (now the Encoder class) LDAP encoding functions:
- `Encoder.LdapFilterEncode(string)` - encodes according to RFC4515
- `Encoder.LdapDistinguishedNameEncode(string)` - encodes according to RFC2253
- `LdapDistinguishedNameEncode(string, bool, bool)` - with optional initial/final character escaping
### Framework-Based Protection
Use frameworks that automatically protect from LDAP injection:
- **Java**: OWASP ESAPI with `encodeForLDAP(String)` and `encodeForDN(String)`
- **.NET**: LINQ to LDAP (for .NET Framework 4.5 or lower) provides automatic LDAP encoding
### Additional Defenses
#### Least Privilege
- Minimize privileges assigned to LDAP binding accounts
- Use read-only accounts where possible
- Avoid administrative accounts for application connections
#### Bind Authentication
- Configure LDAP with bind authentication to add verification and authorization checks
- Prevent anonymous connections and unauthenticated binds
#### Allow-List Input Validation
- Validate input against known-safe characters before LDAP query construction
- Normalize user input before validation
- Store sensitive data in sanitized form
### Key Security Requirements
- Always escape untrusted data before incorporating into LDAP queries
- Use context-appropriate escaping (DN vs search filter)
- Implement comprehensive input validation with allowlists
- Use established security libraries rather than custom escaping
- Apply principle of least privilege to LDAP connections
- Enable proper authentication mechanisms to prevent bypass attacks
================================================
FILE: sources/owasp/codeguard-0-legacy-application-management.md
================================================
---
description: Legacy Application Management Security
languages:
- c
- java
- javascript
- perl
- php
- python
- ruby
- yaml
alwaysApply: false
---
## Legacy Application Management Guidelines
Essential security practices for managing legacy applications that remain in active use despite being outdated.
### Understanding Legacy Application Risks
Legacy applications introduce significant security risks because they:
- May have reached End-of-Life (EoL) with no vendor support or patches
- Use outdated technologies with limited expertise available
- Produce data in custom formats incompatible with modern security tools
- Often have accumulated security vulnerabilities over time
### Inventory and Asset Management
**Inventory Management**: Compile comprehensive documentation identifying legacy applications including:
- Version numbers, production dates, and configuration settings
- Network hosts and infrastructure dependencies
- Services running on hosting infrastructure
- Physical location and access permissions for servers
- Software Bill of Materials (SBOM) for applications with third-party dependencies
**Risk Assessment**: Use industry standard frameworks like NIST Risk Management Framework for formal assessment. Consider these key questions:
- What information is handled/stored and what would be the impact if compromised?
- Do the application/dependencies/infrastructure have known vulnerabilities?
- How critical is application availability to business continuity?
- Could an attacker use this application to access other critical systems?
### Authentication and Authorization
Apply the principle of least privilege with enhanced restrictions for legacy systems:
**Network-Level Controls**:
- Host applications within restricted subnets
- Apply IP allow-listing to prevent arbitrary access
- Consider air-gapped environments for high-risk applications
- Close unnecessary ports on application hosts
- Use firewall rules to restrict port access
**Access Controls**:
- Reduce feature sets available to end users
- Disable high-risk administrative functionalities
- Require authentication via Identity Provider (IdP) services
- Implement VPN access requirements for network environments
- Develop intermediary services/APIs to avoid direct user access to legacy applications
### Vulnerability Management
**Vulnerability Scanning**: Conduct regular automated scanning using industry standard tools:
- Use tools like Nessus and Qualys on scheduled intervals
- Apply Static Application Security Testing (SAST) for code vulnerabilities
- Use Software Composition Analysis (SCA) for dependency vulnerabilities
- Perform manual assessment when automated tools aren't viable
**Patch Management**:
- Prioritize patches based on vulnerability severity and CVE status
- Focus on vulnerabilities with publicly listed exploits
- Apply additional access restrictions when patching isn't possible
### Data Storage Security
Ensure data protection through encryption:
- Encrypt data at rest (database storage)
- Encrypt data in transit with secure protocols
- Apply most restrictive network access controls for applications limited to plain text protocols
- Consider temporary or permanent air-gapping when necessary
### Ensuring Maintainability
Maintain institutional expertise for business continuity:
- Train multiple staff members on legacy application troubleshooting
- Document processes and troubleshooting guides for common failures
- Develop expertise in legacy programming languages within the organization
- Create knowledge transfer programs for new team members
### Change Management
Plan staged migration to modern solutions considering:
- Budget allocation and timeline for upgrading solutions
- Required expertise for migration (internal development or acquisition)
- Migration urgency based on risk profile and organizational risk appetite
Include in change management plans:
- Granular steps toward migration with explicit completion dates
- Clear business and security case for change
- Extensive consultation with existing solution stakeholders
### Continuous Monitoring and Incident Response
Implement enhanced security monitoring with rapid response capabilities:
**Monitoring Solutions**:
- Develop custom APIs to convert legacy application data for modern security tools
- Use automation scripts for compromise indicator reports when APIs aren't possible
- Monitor for anomalous network traffic and activity surges
**Incident Response**:
- Prioritize incident response for critical legacy systems
- Document incident response playbooks with emergency procedures
- Include escalation contacts and incident response leader details
- Integrate incident response with broader business continuity planning
Legacy applications require heightened security measures due to their inherent risks, but with proper controls and planning, organizations can manage these risks while working toward modernization.
================================================
FILE: sources/owasp/codeguard-0-logging-vocabulary.md
================================================
---
description: Standardized Security Event Logging Vocabulary
languages:
- c
- go
- java
- javascript
- kotlin
- php
- python
- ruby
- swift
- typescript
alwaysApply: false
---
## Security Event Logging Vocabulary Guidelines
Standardized vocabulary for logging security events to improve monitoring, alerting, and incident response.
### Standard Event Format
NOTE: All dates should be logged in ISO 8601 format WITH UTC offset to ensure maximum portability
```json
{
"datetime": "2021-01-01T01:01:01-0700",
"appid": "foobar.netportal_auth",
"event": "AUTHN_login_success:joebob1",
"level": "INFO",
"description": "User joebob1 login successfully",
"useragent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36",
"source_ip": "165.225.50.94",
"host_ip": "10.12.7.9",
"hostname": "portalauth.foobar.com",
"protocol": "https",
"port": "440",
"request_uri": "/api/v2/auth/",
"request_method": "POST",
"region": "AWS-US-WEST-2",
"geo": "USA"
}
```
### Authentication Events [AUTHN]
authn_login_success[:userid] - Successful login (Level: INFO)
authn_login_successafterfail[:userid,retries] - Successful login after previous failures (Level: INFO)
authn_login_fail[:userid] - Failed login attempt (Level: WARN)
authn_login_fail_max[:userid,maxlimit] - Maximum failures reached (Level: WARN)
authn_login_lock[:userid,reason] - Account locked (reasons: maxretries, suspicious, customer, other) (Level: WARN)
authn_password_change[:userid] - Password successfully changed (Level: INFO)
authn_password_change_fail[:userid] - Password change failed (Level: CRITICAL)
authn_impossible_travel[:userid,region1,region2] - User in distant locations simultaneously (Level: CRITICAL)
authn_token_created[:userid,entitlements] - Service token created (Level: INFO)
authn_token_revoked[:userid,tokenid] - Token revoked (Level: INFO)
authn_token_reuse[:userid,tokenid] - Revoked token reuse attempt (Level: CRITICAL)
authn_token_delete[:appid] - Token deleted (Level: WARN)
### Authorization Events [AUTHZ]
authz_fail[:userid,resource] - Unauthorized access attempt (Level: CRITICAL)
authz_change[:userid,from,to] - User entitlements changed (Level: WARN)
authz_admin[:userid,event] - All privileged user activity (Level: WARN)
### Encryption/Decryption Events [CRYPT]
crypt_decrypt_fail[userid] - Decryption failure (Level: WARN)
crypt_encrypt_fail[userid] - Encryption failure (Level: WARN)
### Excessive Use Events [EXCESS]
excess_rate_limit_exceeded[userid,max] - Rate limit exceeded (Level: WARN)
### File Upload Events [UPLOAD]
upload_complete[userid,filename,type] - File upload completed (Level: INFO)
upload_stored[filename,from,to] - File stored with new name/location (Level: INFO)
upload_validation[filename,(virusscan|imagemagick|...):(FAILED|incomplete|passed)] - File validation results (Level: INFO|CRITICAL)
upload_delete[userid,fileid] - File deleted (Level: INFO)
### Input Validation Events [INPUT]
input_validation_fail:[(fieldone,fieldtwo...),userid] - Server-side validation failure (Level: WARN)
### Malicious Behavior Events [MALICIOUS]
malicious_excess_404:[userid|IP,useragent] - Excessive 404s indicating force-browsing (Level: WARN)
malicious_extraneous:[userid|IP,inputname,useragent] - Unexpected input data submitted (Level: CRITICAL)
malicious_attack_tool:[userid|IP,toolname,useragent] - Known attack tools detected (Level: CRITICAL)
malicious_cors:[userid|IP,useragent,referer] - Illegal cross-origin request (Level: CRITICAL)
malicious_direct_reference:[userid|IP,useragent] - Direct object reference attempt (Level: CRITICAL)
### Privilege Changes Events [PRIVILEGE]
privilege_permissions_changed:[userid,file|object,fromlevel,tolevel] - Object permissions changed (Level: WARN)
### Sensitive Data Events [DATA]
sensitive_create:[userid,file|object] - Sensitive data created (Level: WARN)
sensitive_read:[userid,file|object] - Sensitive data accessed (Level: WARN)
sensitive_update:[userid,file|object] - Sensitive data modified (Level: WARN)
sensitive_delete:[userid,file|object] - Sensitive data marked for deletion (Level: WARN)
### Sequence Errors Events [SEQUENCE]
sequence_fail:[userid] - Business logic flow bypassed (Level: CRITICAL)
### Session Management Events [SESSION]
session_created:[userid] - New authenticated session (Level: INFO)
session_renewed:[userid] - Session extended after expiry warning (Level: INFO)
session_expired:[userid,reason] - Session expired (reasons: logout, timeout, revoked) (Level: INFO)
session_use_after_expire:[userid] - Expired session use attempt (Level: CRITICAL)
### System Events [SYS]
sys_startup:[userid] - System started (Level: WARN)
sys_shutdown:[userid] - System shut down (Level: WARN)
sys_restart:[userid] - System restarted (Level: WARN)
sys_crash[:reason] - System crash (Level: WARN)
sys_monitor_disabled:[userid,monitor] - Security monitoring disabled (Level: WARN)
sys_monitor_enabled:[userid,monitor] - Security monitoring enabled (Level: WARN)
### User Management Events [USER]
user_created:[userid,newuserid,attributes[one,two,three]] - New user created (Level: WARN)
user_updated:[userid,onuserid,attributes[one,two,three]] - User account updated (Level: WARN)
user_archived:[userid,onuserid] - User account archived (Level: WARN)
user_deleted:[userid,onuserid] - User account deleted (Level: WARN)
### Data Exclusions
Never log sensitive information: private or secret information, source code, keys, certificates, authentication passwords, session identification values, access tokens, sensitive personal data, PII, database connection strings, encryption keys, bank account or payment card data, commercially-sensitive information.
### Implementation Requirements
- Use ISO 8601 format with UTC offset for all timestamps
- Include application identifier (appid) for correlation
- Apply consistent severity levels (INFO, WARN, CRITICAL)
- Include relevant context (IP addresses, user agents, request details)
- Consider data privacy regulations when logging user information
- Fields logged after event type should be considered optional based on business needs and data stewardship responsibilities
================================================
FILE: sources/owasp/codeguard-0-mass-assignment.md
================================================
---
description: Mass Assignment Prevention
languages:
- c
- java
- javascript
- php
- ruby
- scala
alwaysApply: false
---
## Mass Assignment Prevention Guidelines
Essential practices for preventing mass assignment vulnerabilities that allow attackers to modify unintended object properties.
### Understanding Mass Assignment
Mass assignment occurs when frameworks automatically bind HTTP request parameters to program variables or objects. Attackers can exploit this by creating new parameters to overwrite sensitive fields like `isAdmin` or other privilege-related properties.
**Alternative Names by Framework:**
- Mass Assignment: Ruby on Rails, NodeJS
- Autobinding: Spring MVC, ASP NET MVC
- Object injection: PHP
### Vulnerable Example
User form with typical fields:
```html
```
User object with sensitive field:
```java
public class User {
private String userid;
private String password;
private String email;
private boolean isAdmin;
//Getters & Setters
}
```
Vulnerable controller with automatic binding:
```java
@RequestMapping(value = "/addUser", method = RequestMethod.POST)
public String submit(User user) {
userService.add(user);
return "successPage";
}
```
Attack payload:
```text
POST /addUser
userid=bobbytables&password=hashedpass&email=bobby@tables.com&isAdmin=true
```
### Primary Defense Strategies
**1. Use Data Transfer Objects (DTOs)**
Create objects exposing only safe, editable fields:
```java
public class UserRegistrationFormDTO {
private String userid;
private String password;
private String email;
//NOTE: isAdmin field is not present
//Getters & Setters
}
```
**2. Allow-list Approach**
Explicitly define permitted fields for binding.
**3. Block-list Approach**
Explicitly exclude sensitive fields from binding.
### Framework-Specific Implementations
#### Spring MVC
Allow-listing permitted fields:
```java
@Controller
public class UserController {
@InitBinder
public void initBinder(WebDataBinder binder, WebRequest request) {
binder.setAllowedFields(["userid","password","email"]);
}
}
```
Block-listing sensitive fields:
```java
@Controller
public class UserController {
@InitBinder
public void initBinder(WebDataBinder binder, WebRequest request) {
binder.setDisallowedFields(["isAdmin"]);
}
}
```
#### NodeJS + Mongoose
Allow-listing with underscore.js:
```javascript
var UserSchema = new mongoose.Schema({
userid: String,
password: String,
email : String,
isAdmin : Boolean,
});
UserSchema.statics = {
User.userCreateSafeFields: ['userid', 'password', 'email']
};
var User = mongoose.model('User', UserSchema);
_ = require('underscore');
var user = new User(_.pick(req.body, User.userCreateSafeFields));
```
Block-listing with mongoose-mass-assign plugin:
```javascript
var massAssign = require('mongoose-mass-assign');
var UserSchema = new mongoose.Schema({
userid: String,
password: String,
email : String,
isAdmin : { type: Boolean, protect: true, default: false }
});
UserSchema.plugin(massAssign);
var User = mongoose.model('User', UserSchema);
var user = User.massAssign(req.body);
```
#### PHP Laravel + Eloquent
Allow-listing with $fillable:
```php
Received signal to terminate: ${signal}`)
await fastify.close()
// await db.close() if we have a db connection in this app
// await other things we should cleanup nicely
process.exit()
}
process.on('SIGINT', closeGracefully)
process.on('SIGTERM', closeGracefully)
```
### Use Multi-Stage Builds
Separate build and production stages to minimize final image size and prevent secret leakage:
```dockerfile
# --------------> The build image
FROM node:latest AS build
WORKDIR /usr/src/app
COPY package*.json /usr/src/app/
RUN --mount=type=secret,mode=0644,id=npmrc,target=/usr/src/app/.npmrc npm ci --omit=dev
# --------------> The production image
FROM node:lts-alpine@sha256:b2da3316acdc2bec442190a1fe10dc094e7ba4121d029cb32075ff59bb27390a
RUN apk add dumb-init
ENV NODE_ENV production
USER node
WORKDIR /usr/src/app
COPY --chown=node:node --from=build /usr/src/app/node_modules /usr/src/app/node_modules
COPY --chown=node:node . /usr/src/app
CMD ["dumb-init", "node", "server.js"]
```
### Use .dockerignore File
Create a `.dockerignore` file to exclude unnecessary and sensitive files:
```
node_modules
npm-debug.log
Dockerfile
.git
.gitignore
.npmrc
```
This prevents:
- Copying modified local `node_modules/` over the container-built version
- Including sensitive files like credentials or local configuration
- Cache invalidation from log files or temporary files
### Mount Secrets Securely
Use Docker BuildKit secrets to handle sensitive files like `.npmrc`:
```dockerfile
RUN --mount=type=secret,mode=0644,id=npmrc,target=/usr/src/app/.npmrc npm ci --omit=dev
```
Build command:
```bash
docker build . -t nodejs-tutorial --secret id=npmrc,src=.npmrc
```
This ensures secrets are never copied into the final Docker image layers.
### Security Scanning
Regularly scan your Docker images for vulnerabilities using static analysis tools and keep dependencies updated.
By following these practices, you'll create secure, optimized, and maintainable Node.js Docker images suitable for production deployment.
================================================
FILE: sources/owasp/codeguard-0-nodejs-security.md
================================================
---
description: Node.js Security Best Practices
languages:
- c
- javascript
- typescript
alwaysApply: false
---
## Node.js Security Guidelines
Essential security practices for developing secure Node.js applications to prevent common vulnerabilities and attacks.
### Application Security
#### Use Flat Promise Chains
Avoid callback hell and improve error handling by using flat Promise chains or async/await:
```javascript
// Avoid callback hell
func1("input1")
.then(function (result){
return func2("input2");
})
.then(function (result){
return func3("input3");
})
.then(function (result){
return func4("input4");
})
.catch(function (error) {
// error operations
});
```
Using async/await:
```javascript
(async() => {
try {
let res1 = await func1("input1");
let res2 = await func2("input2");
let res3 = await func3("input2");
let res4 = await func4("input2");
} catch(err) {
// error operations
}
})();
```
#### Set Request Size Limits
Prevent resource exhaustion by limiting request body sizes:
```javascript
app.use(express.urlencoded({ extended: true, limit: "1kb" }));
app.use(express.json({ limit: "1kb" }));
```
For custom limits using raw-body:
```JavaScript
const contentType = require('content-type')
const express = require('express')
const getRawBody = require('raw-body')
const app = express()
app.use(function (req, res, next) {
if (!['POST', 'PUT', 'DELETE'].includes(req.method)) {
next()
return
}
getRawBody(req, {
length: req.headers['content-length'],
limit: '1kb',
encoding: contentType.parse(req).parameters.charset
}, function (err, string) {
if (err) return next(err)
req.text = string
next()
})
})
```
#### Perform Input Validation
Use allowlists and sanitize all inputs to prevent injection attacks. Consider modules like validator and express-mongo-sanitize for input validation.
#### Perform Output Escaping
Escape all HTML and JavaScript content to prevent XSS attacks using libraries like escape-html or node-esapi.
#### Monitor Event Loop Health
Use monitoring to detect when your server is overloaded:
```javascript
const toobusy = require('toobusy-js');
app.use(function(req, res, next) {
if (toobusy()) {
res.status(503).send("Server Too Busy");
} else {
next();
}
});
```
#### Prevent Brute Force Attacks
Implement rate limiting and delays for authentication endpoints:
```javascript
const bouncer = require('express-bouncer');
bouncer.blocked = function (req, res, next, remaining) {
res.status(429).send("Too many requests have been made. Please wait " + remaining/1000 + " seconds.");
};
app.post("/login", bouncer.block, function(req, res) {
if (LoginFailed){ }
else {
bouncer.reset( req );
}
});
```
#### Use Anti-CSRF Protection
Protect state-changing requests against Cross-Site Request Forgery. Note: csurf package is deprecated; use alternative CSRF protection packages.
#### Prevent HTTP Parameter Pollution
Use the hpp module to handle multiple parameters with the same name:
```javascript
const hpp = require('hpp');
app.use(hpp());
```
#### Return Only Necessary Data
Limit data exposure by returning only required fields:
```javascript
exports.sanitizeUser = function(user) {
return {
id: user.id,
username: user.username,
fullName: user.fullName
};
};
```
### Error and Exception Handling
#### Handle Uncaught Exceptions
Bind to uncaughtException events to clean up resources before shutdown:
```javascript
process.on("uncaughtException", function(err) {
// clean up allocated resources
// log necessary error details to log files
process.exit(); // exit the process to avoid unknown state
});
```
#### Handle EventEmitter Errors
Always listen to error events when using EventEmitter objects:
```javascript
const events = require('events');
const emitter = new myEventEmitter();
emitter.on('error', function(err){
//Perform necessary error handling here
});
```
### Server Security
#### Set Secure Cookie Flags
Configure cookies with appropriate security flags:
```javascript
const session = require('express-session');
app.use(session({
secret: 'your-secret-key',
name: 'cookieName',
cookie: { secure: true, httpOnly: true, path: '/user', sameSite: true}
}));
```
#### Use Security Headers
Implement security headers using helmet:
```javascript
const helmet = require("helmet");
app.use(helmet()); // Add various HTTP headers
```
Key headers include:
- HSTS: `app.use(helmet.hsts());`
- Frame protection: `app.use(helmet.frameguard());`
- XSS protection: `app.use(helmet.xssFilter());`
- Content Security Policy: `app.use(helmet.contentSecurityPolicy({...}));`
- Content type protection: `app.use(helmet.noSniff());`
- Hide powered by: `app.use(helmet.hidePoweredBy());`
### Platform Security
#### Keep Packages Updated
Regularly audit and update dependencies:
```bash
npm audit
npm audit fix
```
Use tools like OWASP Dependency-Check and Retire.js to identify vulnerable packages.
#### Avoid Dangerous Functions
Exercise caution with potentially dangerous functions:
- Avoid `eval()` with user input (remote code execution risk)
- Be careful with `child_process.exec` (command injection risk)
- Sanitize inputs when using `fs` module (directory traversal risk)
- Use `vm` module within proper sandboxes
#### Prevent ReDoS Attacks
Test regular expressions for denial of service vulnerabilities using tools like vuln-regex-detector.
#### Use Security Linters
Implement static analysis tools like ESLint and JSHint with security-focused rules in your development workflow.
#### Enable Strict Mode
Always use strict mode to catch common JavaScript errors:
```javascript
"use strict";
func();
function func() {
y = 3.14; // This will cause an error (y is not defined)
}
```
### Application Activity Logging
Implement comprehensive logging for security monitoring:
```javascript
const logger = new (Winston.Logger) ({
transports: [
new (winston.transports.Console)(),
new (winston.transports.File)({ filename: 'application.log' })
],
level: 'verbose'
});
```
By following these practices, you can significantly improve the security posture of your Node.js applications and protect against common web application vulnerabilities.
================================================
FILE: sources/owasp/codeguard-0-npm-security.md
================================================
---
description: NPM Security Best Practices
languages:
- javascript
alwaysApply: false
---
## NPM Security Guidelines
Essential security practices for managing NPM packages and dependencies in JavaScript projects.
### Prevent Secret Leakage
Avoid publishing sensitive data to the npm registry:
- Use the `files` property in package.json as an allowlist to control what gets published
- Be cautious with `.gitignore` and `.npmignore` - if both exist, `.npmignore` takes precedence
- Run `npm publish --dry-run` to review the tarball contents before actual publishing
- NPM automatically revokes tokens detected in published packages, but prevention is better
### Enforce Deterministic Builds
Ensure consistent dependency installation across environments:
- Use `npm ci` instead of `npm install` in CI/CD and production builds
- Use `yarn install --frozen-lockfile` if using Yarn
- Never commit changes to package.json without updating the corresponding lockfile
- Lockfile inconsistencies can pull unintended package versions and compromise security
### Minimize Script Execution Risks
Reduce attack surface from package installation scripts:
- Add `--ignore-scripts` when installing packages: `npm install --ignore-scripts`
- Consider adding `ignore-scripts=true` to your `.npmrc` configuration
- Always vet third-party packages for credibility before installation
- Avoid immediate upgrades to new versions; allow time for community review
- Review changelog and release notes before upgrading dependencies
### Monitor Package Health
Regularly assess the state of your dependencies:
- Use `npm outdated` to identify packages that need updates
- Run `npm doctor` to verify healthy npm installation and environment
- Monitor for known vulnerabilities in dependencies using `npm audit`
- Scan for security vulnerabilities in third-party open source projects
- Set up monitoring for new CVEs that impact your project dependencies
### Use Private Registry Solutions
Consider using local npm proxies for enhanced control:
- Verdaccio provides a lightweight private registry solution
- Private registries offer package access control and authenticated users
- Proxy capabilities reduce duplicate downloads and save bandwidth
- Enable routing dependencies to different registries for security control
- Useful for testing environments and mono-repo projects
### Enable Account Security
Protect your npm publishing capabilities:
- Enable two-factor authentication with `npm profile enable-2fa auth-and-writes`
- Use auth-and-writes mode for comprehensive protection of profile, login, and package management
- Auth-only mode provides protection for login and profile changes only
- Use authentication apps like Google Authenticator for 2FA tokens
### Manage Access Tokens Securely
Control programmatic access to npm registry:
- Create tokens with minimal required permissions using `npm token create`
- Use read-only tokens when write access is not needed
- Restrict tokens to specific IP ranges with `--cidr` option
- Regularly audit tokens with `npm token list`
- Revoke unused or compromised tokens immediately with `npm token revoke`
- Never expose tokens in source code, logs, or environment variables
### Defend Against Typosquatting
Protect against malicious package substitution:
- Verify package names and metadata with `npm info ` before installation
- Be extra careful when copy-pasting installation commands from untrusted sources
- Check source code repositories and npm registry to confirm package legitimacy
- Default to being logged out of npm during daily development work
- Use `--ignore-scripts` when installing packages from unknown sources
### Follow Responsible Disclosure
Handle security vulnerabilities appropriately:
- Follow responsible disclosure programs when reporting vulnerabilities
- Coordinate with package maintainers before public disclosure
- Allow time for fixes and upgrade paths before publicizing security issues
- Use proper channels to report security concerns to package authors
### Package Naming Best Practices
Understand npm naming rules and security implications:
- Package names limited to 214 characters, lowercase only
- Cannot start with dot, underscore, or contain special characters like "~\'!()*"
- Be aware that typosquatting attacks target popular package names
- NPM uses spam detection mechanisms for new package publications
- Reserved names include node_modules and favicon.ico
================================================
FILE: sources/owasp/codeguard-0-oauth2.md
================================================
---
description: OAuth 2.0 Security Best Practices
languages:
- c
- go
- java
- javascript
- php
- python
- ruby
- typescript
- yaml
alwaysApply: false
---
## OAuth 2.0 Security Guidelines
Essential security practices for implementing secure OAuth 2.0 authorization flows and protecting against common attacks.
### Essential Basics
Prevent open redirectors that can enable token exfiltration:
- Clients and Authorization Servers must not expose URLs that forward the user's browser to arbitrary URIs obtained from query parameters
- Use exact string matching for redirect URI validation during client registration
Use proper CSRF protection:
- When Authorization Server supports PKCE, clients may rely on PKCE's CSRF protection
- In OpenID Connect flows, the "nonce" parameter provides CSRF protection
- Otherwise, use one-time CSRF tokens in the "state" parameter that are securely bound to the user agent
Prevent mix-up attacks in multi-Authorization Server environments:
- Use the issuer "iss" parameter as a countermeasure when interacting with multiple Authorization Servers
- Alternatively, use distinct redirect URIs to identify different authorization and token endpoints
- Authorization Servers should avoid accidentally forwarding requests containing user credentials
### PKCE - Proof Key for Code Exchange
PKCE mitigates authorization code interception attacks, especially for public clients:
- Use PKCE flow to prevent injection (replay) of authorization codes into authorization responses
- Use PKCE code challenge methods that do not expose the verifier in the authorization request
- Use S256 as the code challenge method instead of plain text
- Authorization servers must support PKCE and enforce correct "code_verifier" usage at the token endpoint
- Prevent PKCE downgrade attacks by accepting "code_verifier" only when "code_challenge" was present in the authorization request
### Authorization Code vs Implicit Grant
Prefer Authorization Code Grant over Implicit Grant:
- Use response type "code" (authorization code grant) or "code id_token" instead of implicit flows
- This allows the Authorization Server to detect replay attempts and reduces attack surface
- Access tokens are not exposed in URLs and can be sender-constrained
### Token Replay Prevention
Implement sender-constraining mechanisms:
- Use Mutual TLS for OAuth 2.0 or OAuth Demonstration of Proof of Possession (DPoP) to prevent token replays
- Implement refresh token rotation or ensure refresh tokens are sender-constrained
### Access Token Privilege Restriction
Apply the principle of least privilege:
- Restrict token privileges to the minimum required for the particular application or use case
- Implement audience restriction by associating access tokens with specific Resource Servers
- Resource Servers must verify that tokens were intended for their use
- Restrict tokens to specific resources and actions using "scope" and "authorization_details" parameters
- Use "scope" and "resource" parameters to determine the intended Resource Server
### Avoid Insecure Grant Types
Never use Resource Owner Password Credentials Grant:
- This grant type insecurely exposes Resource Owner credentials to the client
- Increases the attack surface of the application
### Client Authentication
Use strong authentication methods:
- Implement client authentication whenever possible
- Prefer asymmetric (public-key based) methods like mTLS or "private_key_jwt" (OpenID Connect)
- Asymmetric methods eliminate the need to store sensitive symmetric keys on Authorization Servers
- This approach is more robust against various attacks
### Additional Security Controls
Protect sensitive claims and enforce secure communications:
- Authorization Servers must not allow clients to influence their "client_id" or "sub" values
- Prevent clients from controlling any claims that could be confused with genuine Resource Owner data
- Use end-to-end TLS for all communications
- Never transmit authorization responses over unencrypted network connections
- Prohibit redirect URIs using "http" scheme except for native clients using Loopback Interface Redirection
### Implementation Summary
Secure OAuth 2.0 implementations require:
- PKCE implementation for all public clients
- Proper CSRF protection through state parameters or nonce
- Authorization Code Grant preference over Implicit Grant
- Token sender-constraining mechanisms (mTLS or DPoP)
- Strict privilege restriction and audience validation
- Strong client authentication using asymmetric methods
- Elimination of insecure grant types
- Comprehensive TLS enforcement and redirect URI validation
Following these practices ensures robust protection against authorization code interception, token replay, privilege escalation, and mix-up attacks while maintaining the flexibility and security benefits of OAuth 2.0.
================================================
FILE: sources/owasp/codeguard-0-open-redirect.md
================================================
---
description: Open Redirect Prevention - Secure handling of user-controlled redirects
to prevent phishing attacks
languages:
- c
- javascript
- php
- typescript
- vlang
alwaysApply: false
---
# Avoid Open Redirects
- Never use user input directly as a redirect target (e.g., `res.redirect(userInput)` in Node.js/Express).
- If redirection is controlled by user input:
- Allow only local paths (must start with `/` and not contain protocols like `http:`).
- OR: Allow only destinations present in a strict allowlist of trusted domains.
- URLs must be parsed and validated using robust libraries, not simple substring checks.
- DO NOT allow wildcard domains like `*.example.com` in any allowlist.
- Add explicit code comments when using redirects to document how the rule is being enforced.
================================================
FILE: sources/owasp/codeguard-0-os-command-injection-defense.md
================================================
---
description: OS Command Injection Defense
languages:
- c
- go
- java
- javascript
- perl
- php
- python
- ruby
- shell
alwaysApply: false
---
## OS Command Injection Defense Guidelines
Essential practices for preventing OS command injection vulnerabilities when executing system commands in applications.
### Understanding Command Injection
Command injection occurs when software constructs a system command using externally influenced input without properly neutralizing special elements that can modify the intended command.
Example of vulnerable input:
```
calc & echo "test"
```
This changes the meaning from executing just `calc` to executing both `calc` and `echo "test"`.
#### Argument Injection
Every OS Command Injection is also an Argument Injection, where user input can be passed as arguments while executing a specific command. For example:
```php
system("curl " . escape("--help"))
```
Even with escaping, this shows the output of `curl --help` instead of the intended behavior.
### Primary Defenses
#### Defense Option 1: Avoid Calling OS Commands Directly
The primary defense is to avoid calling OS commands directly. Built-in library functions are preferred as they cannot be manipulated to perform unintended tasks.
Example: Use `mkdir()` instead of `system("mkdir /dir_name")`.
#### Defense Option 2: Escape Values Added to OS Commands
Use language-specific escaping functions when OS commands cannot be avoided.
PHP example using escapeshellarg():
The `escapeshellarg()` function surrounds user input in single quotes, so malformed input like `& echo "hello"` becomes `calc '& echo "hello"'` which is parsed as a single argument.
Note: Even with `escapeshellarg()`, an attacker can still pass a single argument to the command.
#### Defense Option 3: Parameterization with Input Validation
If system commands incorporating user input cannot be avoided, use two layers of defense:
Layer 1 - Parameterization:
Use structured mechanisms that automatically enforce separation between data and command, providing proper quoting and encoding.
Layer 2 - Input Validation:
- Commands: Validate against a list of allowed commands
- Arguments: Use positive/allowlist input validation where arguments are explicitly defined
- Allowlist Regular Expression: Define allowed characters and maximum length, excluding metacharacters
Example regex allowing only lowercase letters and numbers (3-10 characters): `^[a-z0-9]{3,10}$`
POSIX Guideline: Use `--` delimiter to prevent argument injection:
```
curl -- $url
```
This prevents argument injection even if `$url` contains additional arguments.
Dangerous metacharacters to avoid:
```
& | ; $ > < ` \ ! ' " ( )
```
### Code Examples
#### Java
Use ProcessBuilder with separated command and arguments:
Incorrect usage:
```java
ProcessBuilder b = new ProcessBuilder("C:\DoStuff.exe -arg1 -arg2");
```
Correct usage:
```java
ProcessBuilder pb = new ProcessBuilder("TrustedCmd", "TrustedArg1", "TrustedArg2");
Map env = pb.environment();
pb.directory(new File("TrustedDir"));
Process p = pb.start();
```
Note about Runtime.exec:
Java's `Runtime.exec` does NOT invoke the shell and does not support shell metacharacters. It splits strings into arrays and executes the first word with the rest as parameters, making shell-based attacks ineffective.
#### PHP
Use escapeshellarg() or escapeshellcmd() rather than exec(), system(), or passthru().
### Additional Defenses
Implement defense in depth:
- Applications should run with the lowest privileges required for necessary tasks
- Create isolated accounts with limited privileges for single tasks
### Implementation Summary
Secure command execution requires:
- Avoiding OS commands when possible (use built-in libraries)
- Using parameterized execution with separated commands and arguments
- Implementing strict input validation with allowlists
- Applying proper escaping functions when available
- Running applications with minimal privileges
- Using structured mechanisms that enforce data/command separation
Following these practices significantly reduces the risk of OS command injection vulnerabilities in applications.
================================================
FILE: sources/owasp/codeguard-0-password-storage.md
================================================
---
description: Password Storage Security
languages:
- c
- go
- java
- javascript
- php
- python
- ruby
- typescript
alwaysApply: false
---
## Password Storage Security Guidelines
Essential practices for securely storing passwords using modern hashing algorithms to protect against offline attacks.
### Core Principles
Passwords must be hashed, NOT encrypted. Hashing is a one-way function that prevents retrieval of the original password even if the database is compromised. Encryption is reversible and should only be used in rare edge cases where the original password must be recovered.
Strong passwords stored with modern hashing algorithms and proper configuration should be effectively impossible for attackers to crack.
To sum up our recommendations:
- **Use [Argon2id](#argon2id) with a minimum configuration of 19 MiB of memory, an iteration count of 2, and 1 degree of parallelism.**
- **If [Argon2id](#argon2id) is not available, use [scrypt](#scrypt) with a minimum CPU/memory cost parameter of (2^17), a minimum block size of 8 (1024 bytes), and a parallelization parameter of 1.**
- **For legacy systems using [bcrypt](#bcrypt), use a work factor of 10 or more and with a password limit of 72 bytes.**
- **If FIPS-140 compliance is required, use [PBKDF2](#pbkdf2) with a work factor of 600,000 or more and set with an internal hash function of HMAC-SHA-256.**
- **Consider using a [pepper](#peppering) to provide additional defense in depth (though alone, it provides no additional secure characteristics).**
### Recommended Algorithms and Parameters
Use these algorithms in order of preference:
#### Argon2id (Preferred)
Argon2id was the winner of the 2015 Password Hashing Competition and provides balanced resistance to side-channel and GPU-based attacks.
Configuration options (choose one):
- m=47104 (46 MiB), t=1, p=1
- m=19456 (19 MiB), t=2, p=1
- m=12288 (12 MiB), t=3, p=1
- m=9216 (9 MiB), t=4, p=1
- m=7168 (7 MiB), t=5, p=1
All configurations provide equal security with different CPU/RAM trade-offs.
#### scrypt (If Argon2id unavailable)
Configuration options (choose one):
- N=2^17 (128 MiB), r=8 (1024 bytes), p=1
- N=2^16 (64 MiB), r=8 (1024 bytes), p=2
- N=2^15 (32 MiB), r=8 (1024 bytes), p=3
- N=2^14 (16 MiB), r=8 (1024 bytes), p=5
- N=2^13 (8 MiB), r=8 (1024 bytes), p=10
#### bcrypt (Legacy systems only)
Use work factor of 10 or more. Maximum password length is 72 bytes for most implementations.
#### PBKDF2 (FIPS-140 compliance required)
- PBKDF2-HMAC-SHA1: 1,300,000 iterations
- PBKDF2-HMAC-SHA256: 600,000 iterations
- PBKDF2-HMAC-SHA512: 210,000 iterations
### Salting
Modern hashing algorithms (Argon2id, bcrypt, scrypt, PBKDF2) automatically handle salting. Salts must be:
- Unique for every password
- Generated using a cryptographically secure random number generator
- Stored alongside the hash
Never manually implement salting when using modern algorithms.
### Peppering (Optional Defense in Depth)
A pepper is a secret value shared between stored passwords, unlike salts which are unique per password. Peppers provide additional protection if the database is compromised but the application server remains secure.
Requirements for peppering:
- Store pepper separately from the password database
- Use secure storage (secrets vaults, HSMs)
- Generate securely using cryptographically strong methods
- Changing pepper requires all users to reset passwords
Implementation strategies:
- Pre-hashing: Add pepper to password before hashing
- Post-hashing: HMAC the password hash with pepper as key
### Work Factor Tuning
Balance security and performance by adjusting work factors:
- Target less than one second for hash calculation
- Increase work factors over time as hardware improves
- Test on your specific server hardware
- Higher work factors slow down both legitimate authentication and attacker cracking
### Upgrading Legacy Hashes
For applications using weak algorithms (MD5, SHA-1):
Method 1: Force password reset
- Expire old hashes for inactive users
- Require password reset on next login
- More secure but less user-friendly
Method 2: Layer hashing
- Use existing hash as input to secure algorithm
- Example: `bcrypt(md5($password))`
- Upgrade to direct hashing when user next authenticates
- Store algorithm and parameters using PHC string format
### bcrypt Pre-Hashing Considerations
If pre-hashing with bcrypt is necessary:
- Use `bcrypt(base64(hmac-sha384(data:$password, key:$pepper)), $salt, $cost)`
- Store pepper outside database
- Avoid simple pre-hashing like `bcrypt(sha512($password))` due to password shucking vulnerability
### International Character Support
Password hashing libraries must:
- Accept full Unicode character range
- Support null bytes in passwords
- Preserve entropy without reduction
- Handle characters from various languages and pictograms
### Performance Guidelines
- Hash calculation should take less than one second
- Benchmark on production hardware
- Monitor authentication performance
- Adjust parameters based on server capacity and user load
- Consider denial of service risks from overly high work factors
### Implementation Summary
Secure password storage requires:
- Modern slow hashing algorithms (Argon2id preferred)
- Proper algorithm configuration with adequate work factors
- Automatic salt handling by the hashing library
- Optional pepper for defense in depth
- Upgrade path for legacy hashes
- Performance tuning for your environment
- Support for international characters
Following these practices protects user passwords against offline attacks even if the database is compromised.
================================================
FILE: sources/owasp/codeguard-0-php-configuration.md
================================================
---
description: PHP Secure Configuration
languages:
- php
alwaysApply: false
---
## PHP Secure Configuration Guidelines
Essential security settings for PHP configuration to harden PHP applications against common vulnerabilities.
### PHP Version Management
Run a supported version of PHP. As of this writing, 8.1 is the oldest version receiving security support from PHP, though distribution vendors often provide extended support.
### Error Handling Configuration
Configure proper error handling to prevent information disclosure while ensuring errors are logged:
```ini
expose_php = Off
error_reporting = E_ALL
display_errors = Off
display_startup_errors = Off
log_errors = On
error_log = /valid_path/PHP-logs/php_error.log
ignore_repeated_errors = Off
```
Keep `display_errors` to `Off` on production servers and monitor the logs frequently.
### General Security Settings
```ini
doc_root = /path/DocumentRoot/PHP-scripts/
open_basedir = /path/DocumentRoot/PHP-scripts/
include_path = /path/PHP-pear/
extension_dir = /path/PHP-extensions/
mime_magic.magicfile = /path/PHP-magic.mime
allow_url_fopen = Off
allow_url_include = Off
variables_order = "GPCS"
allow_webdav_methods = Off
session.gc_maxlifetime = 600
```
`allow_url_*` prevents LFIs from being easily escalated to RFIs.
### File Upload Handling
```ini
file_uploads = On
upload_tmp_dir = /path/PHP-uploads/
upload_max_filesize = 2M
max_file_uploads = 2
```
If your application is not using file uploads, `file_uploads` should be turned `Off`.
### Executable Handling
```ini
enable_dl = Off
disable_functions = system, exec, shell_exec, passthru, phpinfo, show_source, highlight_file, popen, proc_open, fopen_with_path, dbmopen, dbase_open, putenv, move_uploaded_file, chdir, mkdir, rmdir, chmod, rename, filepro, filepro_rowcount, filepro_retrieve, posix_mkfifo
disable_classes =
```
These are dangerous PHP functions. Disable all functions that you don't use.
### Session Handling
Session settings are some of the most important values to concentrate on in configuring. It is a good practice to change `session.name` to something new.
```ini
session.save_path = /path/PHP-session/
session.name = myPHPSESSID
session.auto_start = Off
session.use_trans_sid = 0
session.cookie_domain = full.qualified.domain.name
#session.cookie_path = /application/path/
session.use_strict_mode = 1
session.use_cookies = 1
session.use_only_cookies = 1
session.cookie_lifetime = 14400 # 4 hours
session.cookie_secure = 1
session.cookie_httponly = 1
session.cookie_samesite = Strict
session.cache_expire = 30
session.sid_length = 256
session.sid_bits_per_character = 6
```
### Additional Security Settings
```ini
session.referer_check = /application/path
memory_limit = 50M
post_max_size = 20M
max_execution_time = 60
report_memleaks = On
html_errors = Off
zend.exception_ignore_args = On
```
### Advanced Protection with Snuffleupagus
Snuffleupagus is the spiritual descendant of Suhosin for PHP 7 and onwards, with modern features. It's considered stable and is usable in production.
### Implementation Summary
Secure PHP configuration requires:
- Hiding PHP version information (expose_php = Off)
- Proper error handling with logging enabled but display disabled in production
- Disabling remote file access (allow_url_fopen/include = Off)
- Restricting dangerous functions based on application needs
- Hardening session management with secure cookie settings
- Setting appropriate resource limits to prevent DoS
- Using modern security extensions like Snuffleupagus
Following these configuration practices significantly reduces the attack surface of PHP applications and protects against common vulnerabilities.
================================================
FILE: sources/owasp/codeguard-0-pinning.md
================================================
---
description: Certificate and Public Key Pinning Security
languages:
- c
- java
- javascript
- kotlin
- matlab
- swift
- typescript
- xml
alwaysApply: false
---
## Certificate and Public Key Pinning Guidelines
Essential practices for implementing certificate and public key pinning to prevent Man-in-the-Middle attacks in hostile environments.
### Understanding the Problem
TLS channels can be vulnerable to MITM attacks when certificate-based trust is compromised through:
1. Attackers acquiring rogue certificates from trusted CAs for victim sites
2. Attackers injecting dangerous CAs into client trust stores
Pinning associates a host with its expected X509 certificate or public key, creating a pinset that advertised credentials must match.
### When NOT to Pin (Critical Decision Criteria)
Avoid pinning in these situations:
- You don't control both client and server sides of the connection
- You cannot update the pinset securely without app redeployment
- Certificate key pairs cannot be predicted before being put into service
- Application is not a native mobile application
- Updating pinset is disruptive to operations
The risk of outages almost always outweighs security benefits given modern certificate authority security advancements.
### When Pinning May Be Appropriate
Consider pinning only when:
- You control both endpoints and can manage certificate lifecycles
- You can implement secure pin update mechanisms
- Your threat model specifically requires protection against CA compromise
- You have tested thoroughly and planned for certificate rotation
### Implementation Approaches by Platform
#### Android
Use Android's Network Security Configuration feature with `` configuration settings. Alternatively, use established libraries like OkHTTP for programmatic pinning. Avoid implementing custom SSL validation from scratch.
#### iOS
Apple suggests pinning CA public keys via `Info.plist` under App Transport Security Settings. Use TrustKit library for easier implementation. Custom implementation requires SecTrustEvaluate logic following HTTPS Server Trust Evaluation guidelines.
#### .Net
Implement using ServicePointManager callbacks for certificate validation.
#### OpenSSL
Use verify_callback or post-connection validation via SSL_get_peer_certificate. Must call SSL_get_verify_result (verify X509_V_OK) and SSL_get_peer_certificate (verify non-NULL). Fail connection and tear down socket on validation errors.
#### Electron
Use electron-ssl-pinning library or ses.setCertificateVerifyProc for custom certificate validation.
### What to Pin
Pin selection strategy:
1. Leaf certificate pinning (recommended): Provides 100% certainty but requires backup pins for intermediate CAs to prevent app breakage during certificate rotation
2. Intermediate CA pinning: Reduces risk but trusts all certificates issued by that CA
3. Root CA pinning: Not recommended due to high risk from trusting all intermediate CAs
Pin type options:
- Whole certificate: Easiest to implement but requires frequent updates for certificate rotation
- Public key (subjectPublicKeyInfo): More flexible, allows certificate renewal with same key, provides access to key parameters and algorithm context
- Hash: Convenient and fixed-length but lacks contextual information
Prefer subjectPublicKeyInfo pinning for balance of flexibility and security context.
### Pin Management Best Practices
#### Pin Addition Timing
Add pins at development time (preloading) rather than Trust On First Use (TOFU). Preloading out-of-band prevents attackers from tainting pins.
#### Backup Strategy
Always include backup pins (intermediate CA or alternate certificates) to prevent application outages during certificate updates.
#### Update Mechanisms
Plan secure pin update methods that don't require app redeployment. Consider remote configuration with authenticated channels.
#### Failure Handling
Never allow users to bypass pin validation failures. Log failures client-side but terminate connections on pin mismatches.
### Corporate Environment Considerations
For organizations using interception proxies as part of Data Loss Prevention:
- Do not automatically allow-list interception proxies
- Add proxy public keys to pinset only after explicit risk acceptance approval
- Treat corporate proxies as "good bad actors" that still break end-to-end security
### Testing and Validation
Thoroughly test pinning implementations using OWASP Mobile Security Testing Guide network communication guidelines:
- Verify pin validation occurs correctly
- Test certificate rotation scenarios
- Validate failure handling paths
- Ensure backup pins function properly
### Operational Considerations
#### Certificate Lifecycle Management
- Coordinate with backend teams on certificate rotation schedules
- Plan pin updates in advance of certificate expiration
- Monitor certificate validity periods
- Implement alerts for approaching pin expiration
#### Risk Assessment
Understand that pinning creates operational risk of application outages if not managed properly. The security benefit must outweigh availability risks for your specific threat model.
### Common Implementation Errors to Avoid
- Custom TLS or pinning implementations instead of vetted libraries
- Pinning without backup strategies
- Allowing user bypass of pin failures
- Inadequate testing of certificate rotation scenarios
- Pinning root CAs without understanding the expanded trust implications
### Summary
Certificate and public key pinning can provide additional protection against sophisticated MITM attacks but introduces significant operational complexity and availability risks. Most applications should rely on standard certificate validation rather than implementing pinning. When pinning is necessary, use platform-native solutions or well-established libraries, implement comprehensive backup strategies, and thoroughly test all scenarios including certificate rotation.
================================================
FILE: sources/owasp/codeguard-0-prototype-pollution-prevention.md
================================================
---
description: Prototype Pollution Prevention
languages:
- javascript
- typescript
alwaysApply: false
---
# Prototype Pollution Prevention Guideline
## Explanation
Prototype Pollution is a critical vulnerability that can allow attackers to manipulate an application's JavaScript objects and properties, leading to serious security issues such as unauthorized access to data, privilege escalation, and even remote code execution.
## Suggested protection mechanisms
### Use "new Set()" or "new Map()"
Developers should use `new Set()` or `new Map()` instead of using object literals:
```javascript
let allowedTags = new Set();
allowedTags.add('b');
if(allowedTags.has('b')){
//...
}
let options = new Map();
options.set('spaces', 1);
let spaces = options.get('spaces')
```
### If objects or object literals are required
If objects have to be used then they should be created using the `Object.create(null)` API to ensure they don't inherit from the Object prototype:
```javascript
let obj = Object.create(null);
```
If object literals are required then as a last resort you could use the `__proto__` property:
```javascript
let obj = {__proto__:null};
```
### Use object "freeze" and "seal" mechanisms
You can also use the `Object.freeze()` and `Object.seal()` APIs to prevent built-in prototypes from being modified however this can break the application if the libraries they use modify the built-in prototypes.
### Node.js configuration flag
Node.js also offers the ability to remove the `__proto__` property completely using the `--disable-proto=delete` flag. Note this is a defense in depth measure.
Prototype pollution is still possible using `constructor.prototype` properties but removing `__proto__` helps reduce attack surface and prevent certain attacks.
### Other resources
- [What is prototype pollution? (Portswigger Web Security Academy)](https://portswigger.net/web-security/prototype-pollution)
- [Prototype pollution (Snyk Learn)](https://learn.snyk.io/lessons/prototype-pollution/javascript/)
### Credits
Credit to [Gareth Hayes](https://garethheyes.co.uk/) for providing the original protection guidance [in this comment](https://github.com/OWASP/ASVS/issues/1563#issuecomment-1470027723).
================================================
FILE: sources/owasp/codeguard-0-query-parameterization.md
================================================
---
description: SQL Injection Prevention via Query Parameterization
languages:
- c
- java
- perl
- php
- ruby
- rust
- sql
alwaysApply: false
---
## Query Parameterization Guidelines
Essential practices for preventing SQL injection attacks by using parameterized queries instead of string concatenation when building database queries.
### Core Principle
SQL injection is prevented through parameterized queries that separate SQL structure from data. User input is treated as data parameters, not executable SQL code, preventing attackers from altering query structure.
### Implementation Requirements
Always use language-specific parameterized queries or prepared statements:
#### Java with PreparedStatement
```java
String custname = request.getParameter("customerName");
String query = "SELECT account_balance FROM user_data WHERE user_name = ? ";
PreparedStatement pstmt = connection.prepareStatement( query );
pstmt.setString( 1, custname);
ResultSet results = pstmt.executeQuery( );
```
#### Java with Hibernate
```java
// HQL
@Entity // declare as entity;
@NamedQuery(
name="findByDescription",
query="FROM Inventory i WHERE i.productDescription = :productDescription"
)
public class Inventory implements Serializable {
@Id
private long id;
private String productDescription;
}
// Use case
// This should REALLY be validated too
String userSuppliedParameter = request.getParameter("Product-Description");
// Perform input validation to detect attacks
List list =
session.getNamedQuery("findByDescription")
.setParameter("productDescription", userSuppliedParameter).list();
// Criteria API
// This should REALLY be validated too
String userSuppliedParameter = request.getParameter("Product-Description");
// Perform input validation to detect attacks
Inventory inv = (Inventory) session.createCriteria(Inventory.class).add
(Restrictions.eq("productDescription", userSuppliedParameter)).uniqueResult();
```
#### .NET with OleDbCommand
```csharp
String query = "SELECT account_balance FROM user_data WHERE user_name = ?";
try {
OleDbCommand command = new OleDbCommand(query, connection);
command.Parameters.Add(new OleDbParameter("customerName", CustomerName Name.Text));
OleDbDataReader reader = command.ExecuteReader();
// …
} catch (OleDbException se) {
// error handling
}
```
#### ASP.NET with SqlCommand
```csharp
string sql = "SELECT * FROM Customers WHERE CustomerId = @CustomerId";
SqlCommand command = new SqlCommand(sql);
command.Parameters.Add(new SqlParameter("@CustomerId", System.Data.SqlDbType.Int));
command.Parameters["@CustomerId"].Value = 1;
```
#### Ruby with ActiveRecord
```ruby
## Create
Project.create!(:name => 'owasp')
## Read
Project.all(:conditions => "name = ?", name)
Project.all(:conditions => { :name => name })
Project.where("name = :name", :name => name)
## Update
project.update_attributes(:name => 'owasp')
## Delete
Project.delete(:name => 'name')
```
#### Ruby Built-in
```ruby
insert_new_user = db.prepare "INSERT INTO users (name, age, gender) VALUES (?, ? ,?)"
insert_new_user.execute 'aizatto', '20', 'male'
```
#### PHP with PDO
```php
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value);
```
#### Cold Fusion
```coldfusion
SELECT * FROM #strDatabasePrefix#_courses WHERE intCourseID =
```
#### Perl with DBI
```perl
my $sql = "INSERT INTO foo (bar, baz) VALUES ( ?, ? )";
my $sth = $dbh->prepare( $sql );
$sth->execute( $bar, $baz );
```
#### Rust with SQLx
```rust
// Input from CLI args but could be anything
let username = std::env::args().last().unwrap();
// Using build-in macros (compile time checks)
let users = sqlx::query_as!(
User,
"SELECT * FROM users WHERE name = ?",
username
)
.fetch_all(&pool)
.await
.unwrap();
// Using built-in functions
let users: Vec = sqlx::query_as::<_, User>(
"SELECT * FROM users WHERE name = ?"
)
.bind(&username)
.fetch_all(&pool)
.await
.unwrap();
```
### Stored Procedure Security
#### Normal Stored Procedures
Parameters are naturally bound without special requirements:
##### Oracle PL/SQL
```sql
PROCEDURE SafeGetBalanceQuery(UserID varchar, Dept varchar) AS BEGIN
SELECT balance FROM accounts_table WHERE user_ID = UserID AND department = Dept;
END;
```
##### SQL Server T-SQL
```sql
PROCEDURE SafeGetBalanceQuery(@UserID varchar(20), @Dept varchar(10)) AS BEGIN
SELECT balance FROM accounts_table WHERE user_ID = @UserID AND department = @Dept
END
```
#### Dynamic SQL in Stored Procedures
Use bind variables to ensure dynamic SQL treats inputs as data, not code:
##### Oracle with EXECUTE IMMEDIATE
```sql
PROCEDURE AnotherSafeGetBalanceQuery(UserID varchar, Dept varchar)
AS stmt VARCHAR(400); result NUMBER;
BEGIN
stmt := 'SELECT balance FROM accounts_table WHERE user_ID = :1
AND department = :2';
EXECUTE IMMEDIATE stmt INTO result USING UserID, Dept;
RETURN result;
END;
```
##### SQL Server with sp_executesql
```sql
PROCEDURE SafeGetBalanceQuery(@UserID varchar(20), @Dept varchar(10)) AS BEGIN
DECLARE @sql VARCHAR(200)
SELECT @sql = 'SELECT balance FROM accounts_table WHERE '
+ 'user_ID = @UID AND department = @DPT'
EXEC sp_executesql @sql,
'@UID VARCHAR(20), @DPT VARCHAR(10)',
@UID=@UserID, @DPT=@Dept
END
```
### Critical Security Notes
- Ensure parameterization occurs server-side; client-side parameterization libraries may still build unsafe queries through string concatenation
- Parameterized queries are the primary defense against SQL injection
- Input validation should focus on business logic requirements, not SQL injection prevention
- Never concatenate user input directly into SQL query strings
- Use bind variables for any dynamic SQL construction within stored procedures
================================================
FILE: sources/owasp/codeguard-0-rest-assessment.md
================================================
---
description: RESTful Web Service Security Assessment Guidelines
languages:
- c
- go
- java
- javascript
- python
- ruby
- typescript
- xml
- yaml
alwaysApply: false
---
## RESTful Web Service Security Assessment Guidelines
Essential practices for security testing and assessment of RESTful web services, focusing on identifying attack surfaces and testing methodologies.
### Understanding REST Security Challenges
RESTful web services present unique security testing challenges:
- Attack surface is not visible through application inspection since client applications often don't utilize all available service functions
- Parameters may be embedded in URL paths, custom headers, or structured data rather than standard query strings
- Large parameter sets in JSON/XML structures significantly increase testing complexity
- Custom authentication mechanisms require reverse engineering and may not work with standard testing tools
- Lack of formal documentation makes comprehensive testing difficult
### REST Service Characteristics
Key properties that impact security assessment:
- Primary operations use HTTP methods (GET, POST, PUT, DELETE)
- Non-standard parameter locations including URL segments and custom headers
- Structured parameters and responses using JSON or XML formats
- Custom authentication and session management with security tokens
- Machine-to-machine communication without traditional login sequences
### Attack Surface Discovery
#### Documentation-Based Discovery
Obtain service information for comprehensive coverage:
- Formal service descriptions (WSDL 2.0, WADL) when available
- Developer guides and API documentation
- Application source code or configuration files
- Framework configuration files (especially .NET) that may reveal REST service definitions
#### Proxy-Based Request Collection
Use capable proxy tools to collect complete HTTP interactions:
- Capture full requests including headers and body content, not just URLs
- REST services utilize more than GET parameters requiring complete request analysis
- Dynamic client-side activation may not provide visible links for inspection
#### Parameter Identification Techniques
Analyze collected requests to identify non-standard parameters:
- Abnormal HTTP headers often indicate header-based parameters
- URL segments with repeating patterns (dates, numbers, ID-like strings) suggest URL-embedded parameters
- URLs without extensions in the final segment, especially when other segments have extensions
- Highly varying URL segments with many different values indicate parameters rather than physical directories
- Structured parameter values in JSON, XML, or custom formats
### Parameter Verification Methods
Distinguish between path elements and parameters:
- Set suspected parameter values to invalid inputs
- Web server returns 404 for invalid path elements
- Application returns application-level error messages for invalid parameter values
- This technique helps confirm parameter identification but doesn't work in all cases
### Fuzzing Optimization Strategies
Analyze collected parameter values to optimize testing:
- Identify valid versus invalid value patterns
- Focus fuzzing on marginal invalid values (e.g., zero for positive integers)
- Identify sequences to test beyond current user's allocated range
- Understand parameter relationships and dependencies
### Authentication Mechanism Handling
Address custom authentication challenges:
- Reverse engineer custom token-based authentication
- Ensure fuzzing tools properly emulate authentication mechanisms
- Account for session management differences in machine-to-machine communication
- Test authentication bypass and privilege escalation scenarios
### Testing Methodology Best Practices
Systematic approach to REST service assessment:
- Combine documentation review with dynamic analysis
- Use proxy tools capable of handling complete HTTP transactions
- Systematically identify and verify parameter locations
- Optimize fuzzing based on observed parameter patterns
- Maintain authentication context throughout testing
- Document discovered endpoints and parameter structures
### Documentation and Formal Descriptions
Improve assessment efficiency through proper documentation:
- Encourage use of formal service descriptions (WADL, WSDL 2.0)
- Provide comprehensive developer guides for security assessors
- Document all endpoints, parameters, and expected data formats
- Include authentication and authorization requirements
### Security Testing Coverage
Ensure comprehensive security assessment:
- Test all HTTP methods supported by each endpoint
- Validate input handling for all parameter locations (URL, headers, body)
- Test authentication and authorization mechanisms
- Assess rate limiting and denial-of-service protections
- Verify proper error handling and information disclosure prevention
This assessment methodology helps identify security vulnerabilities in RESTful web services by addressing the unique challenges they present compared to traditional web applications.
================================================
FILE: sources/owasp/codeguard-0-rest-security.md
================================================
---
description: REST API Security Guidelines
languages:
- c
- go
- java
- javascript
- php
- python
- ruby
- typescript
- xml
- yaml
alwaysApply: false
---
## REST API Security Guidelines
Essential security practices for developing secure RESTful web services, covering transport security, authentication, input validation, and proper error handling.
### Core REST Security Principles
REST APIs are stateless - each request must contain all necessary information for processing. State refers to resource state, not session state. Avoid passing client state to backend as this creates replay and impersonation attack vectors.
Each REST endpoint must independently verify authorization for the requested operation on the specific resource.
### HTTPS Requirements
Secure REST services must only provide HTTPS endpoints to protect:
- Authentication credentials (passwords, API keys, JSON Web Tokens)
- Data integrity and confidentiality
- Client authentication of the service
Consider mutually authenticated client-side certificates for highly privileged web services.
### Access Control
Non-public REST services must perform access control at each API endpoint:
- Take access control decisions locally at REST endpoints to minimize latency
- Use centralized Identity Provider (IdP) for user authentication that issues access tokens
- Avoid relying on global session state across distributed services
### JWT Security
When using JSON Web Tokens for security tokens:
Essential Requirements:
- Ensure JWTs are integrity protected by signature or MAC
- Never allow unsecured JWTs with `{"alg":"none"}`
- Prefer signatures over MACs for integrity protection
- Verify JWT integrity based on local configuration, not JWT header information
Standard Claims Validation:
- `iss` (issuer): Verify trusted issuer and signing key ownership
- `aud` (audience): Confirm relying party is in target audience
- `exp` (expiration): Validate current time is before token expiration
- `nbf` (not before): Validate current time is after token validity start
Token Revocation:
- Implement JWT denylist for explicit session termination
- Submit hash of revoked JWTs to denylist until natural expiration
### API Keys
For public REST services requiring access control:
- Require API keys for every request to protected endpoints
- Return `429 Too Many Requests` for rate limit violations
- Revoke API keys for usage agreement violations
- Do not rely exclusively on API keys for sensitive or high-value resources
### HTTP Method Restrictions
- Apply allowlist of permitted HTTP methods (GET, POST, PUT, DELETE)
- Reject unauthorized methods with `405 Method not allowed`
- Verify caller authorization for specific HTTP method on resource
- Be especially careful with Java EE HTTP verb tampering vulnerabilities
### Input Validation
Never trust input parameters or objects:
- Validate input length, range, format, and type
- Use strong types (numbers, booleans, dates) for implicit validation
- Constrain string inputs with regular expressions
- Reject unexpected or illegal content
- Define appropriate request size limits, return `413 Request Entity Too Large`
- Log input validation failures for attack detection
- Use secure parsers resistant to XXE and similar attacks
### Content Type Validation
Request Validation:
- Reject requests with unexpected or missing Content-Type headers (`406 Unacceptable` or `415 Unsupported Media Type`)
- Allow missing Content-Type only for Content-Length: 0 requests
- Explicitly define supported content types in framework configurations
- Ensure XML parser hardening against XXE attacks
Response Security:
- Never copy Accept header directly to Content-Type response header
- Reject requests with unsupported Accept headers (`406 Not Acceptable`)
- Send intended content type headers matching response body content
### Management Endpoints
- Avoid exposing management endpoints via Internet
- Require strong authentication (multi-factor) if Internet-accessible
- Use different HTTP ports, hosts, or network interfaces
- Restrict access via firewall rules or access control lists
### Error Handling
- Respond with generic error messages
- Never reveal technical details (call stacks, internal hints) to clients
- Avoid exposing system information that aids attackers
### Audit Logging
- Write audit logs before and after security-related events
- Log token validation errors for attack detection
- Sanitize log data to prevent log injection attacks
### Security Headers
Include these headers in all API responses:
Required Headers:
- `Cache-Control: no-store`: Prevents sensitive information caching
- `Content-Security-Policy: frame-ancestors 'none'`: Prevents clickjacking
- `Content-Type`: Specify correct content type to prevent MIME sniffing
- `Strict-Transport-Security`: Enforce HTTPS-only access
- `X-Content-Type-Options: nosniff`: Prevent MIME type confusion
- `X-Frame-Options: DENY`: Additional clickjacking protection
### CORS Configuration
- Disable CORS headers if cross-domain calls are not required
- Be as specific as possible when setting allowed origins
- Avoid wildcard origins in production environments
### Sensitive Information Protection
Never include sensitive data in URLs:
- Use request body or headers for POST/PUT sensitive data
- Use HTTP headers for GET request sensitive data
- Avoid query parameters for passwords, tokens, or API keys
- URLs may be logged by web servers, proxies, and browsers
### HTTP Status Codes
Use semantically appropriate status codes:
- `200 OK`: Successful operations
- `201 Created`: Resource creation with Location header
- `400 Bad Request`: Malformed requests
- `401 Unauthorized`: Authentication required
- `403 Forbidden`: Authorization failed
- `404 Not Found`: Resource not found
- `405 Method Not Allowed`: HTTP method not supported
- `406 Not Acceptable`: Unsupported Accept header
- `413 Payload Too Large`: Request size exceeded
- `415 Unsupported Media Type`: Unsupported Content-Type
- `429 Too Many Requests`: Rate limiting triggered
- `500 Internal Server Error`: Generic server error (no details)
### Implementation Summary
Secure REST API development requires:
- HTTPS-only endpoints with proper certificate validation
- Stateless design with per-endpoint authorization
- Secure JWT handling with proper validation and revocation
- Comprehensive input validation and content type enforcement
- Protected management interfaces with strong authentication
- Generic error responses without information disclosure
- Complete audit logging with injection prevention
- Appropriate security headers for defense in depth
- Careful CORS configuration and sensitive data handling
- Semantically correct HTTP status codes for proper client behavior
================================================
FILE: sources/owasp/codeguard-0-ruby-on-rails.md
================================================
---
description: Ruby on Rails Security Guidelines
languages:
- c
- javascript
- ruby
- typescript
- yaml
alwaysApply: false
---
## Ruby on Rails Security Guidelines
Essential security practices for developing secure Ruby on Rails applications.
### Command Injection Prevention
Avoid these dangerous methods with user input:
```ruby
eval("ruby code here")
system("os command here")
`ls -al /` # (backticks contain os command)
exec("os command here")
spawn("os command here")
open("| os command here")
Process.exec("os command here")
Process.spawn("os command here")
IO.binread("| os command here")
IO.binwrite("| os command here", "foo")
IO.foreach("| os command here") {}
IO.popen("os command here")
IO.read("| os command here")
IO.readlines("| os command here")
IO.write("| os command here", "foo")
```
Use allowlists and validation when system interaction is necessary.
### SQL Injection Prevention
```ruby
# DANGEROUS - Injectable
name = params[:name]
@projects = Project.where("name like '" + name + "'");
# SAFE - Use parameterized queries
@projects = Project.where("name like ?", "%#{ActiveRecord::Base.sanitize_sql_like(params[:name])}%")
```
### XSS Prevention
Rails auto-escapes by default. Avoid bypassing protection:
```ruby
# DANGEROUS - Do not do this
<%= raw @product.name %>
<%== @product.name %>
<%= @product.name.html_safe %>
```
Use `sanitize` helper for limited HTML with allowed tags only.
### Session Management
Use database-backed sessions for better security:
```ruby
Project::Application.config.session_store :active_record_store
```
### Transport Security
Force HTTPS in production:
```ruby
# config/environments/production.rb
config.force_ssl = true
```
### Authentication with Devise
```bash
gem 'devise'
rails generate devise:install
```
Configure routes:
```ruby
Rails.application.routes.draw do
authenticate :user do
resources :something do # these resource require authentication
...
end
end
devise_for :users # sign-up/-in/out routes
root to: 'static#home' # no authentication required
end
```
Password complexity with zxcvbn:
```ruby
class User < ApplicationRecord
devise :database_authenticatable,
# other devise features, then
:zxcvbnable
end
```
```ruby
# in config/initializers/devise.rb
Devise.setup do |config|
config.min_password_score = 4 # complexity score here.
...
```
### Token Authentication
```bash
gem 'devise_token_auth'
gem 'omniauth'
```
```ruby
mount_devise_token_auth_for 'User', at: 'auth'
```
### CSRF Protection
```ruby
class ApplicationController < ActionController::Base
protect_from_forgery
```
Token authentication doesn't require CSRF protection.
### Secure Redirects
```ruby
# DANGEROUS
redirect_to params[:url]
# SAFE
begin
if path = URI.parse(params[:url]).path
redirect_to path
end
rescue URI::InvalidURIError
redirect_to '/'
end
```
Use allowlists for multiple redirect targets:
```ruby
ACCEPTABLE_URLS = {
'our_app_1' => "https://www.example_commerce_site.com/checkout",
'our_app_2' => "https://www.example_user_site.com/change_settings"
}
def redirect
url = ACCEPTABLE_URLS["#{params[:url]}"]
redirect_to url if url
end
```
### CORS Configuration
```ruby
# Gemfile
gem 'rack-cors', :require => 'rack/cors'
# config/application.rb
module Sample
class Application < Rails::Application
config.middleware.use Rack::Cors do
allow do
origins 'someserver.example.com'
resource %r{/users/\d+.json},
:headers => ['Origin', 'Accept', 'Content-Type'],
:methods => [:post, :get]
end
end
end
end
```
### Security Headers
```ruby
ActionDispatch::Response.default_headers = {
'X-Frame-Options' => 'SAMEORIGIN',
'X-Content-Type-Options' => 'nosniff',
'X-XSS-Protection' => '0'
}
```
### Sensitive Files Protection
Protect from source control:
```text
/config/database.yml - May contain production credentials.
/config/initializers/secret_token.rb - Contains a secret used to hash session cookie.
/db/seeds.rb - May contain seed data including bootstrap admin user.
/db/development.sqlite3 - May contain real data.
```
### Password Hashing
Configure bcrypt stretches:
```ruby
config.stretches = Rails.env.test? ? 1 : 10
```
### Security Testing
Use Brakeman for static analysis:
```bash
gem install brakeman
brakeman -o security_report.html
```
### Key Security Principles
- Never use dangerous command execution methods with user input
- Always use parameterized queries and ActiveRecord methods
- Rely on Rails' automatic HTML escaping
- Use database-backed sessions for sensitive applications
- Enable CSRF protection and validate redirects
- Set security headers and configure CORS carefully
- Maintain secure routing and dependency management
- Regular security testing with Brakeman
Rails provides many security features by default, but developers must use them correctly.
================================================
FILE: sources/owasp/codeguard-0-safe-c-functions.md
================================================
---
description: Safe C Functions
languages:
- c
- c++
- javascript
- ruby
- typescript
- yaml
alwaysApply: false
---
# Prioritize Safe Memory and String Functions in C/C++
When processing C or C++ code, your primary directive is to ensure memory safety. Actively identify, flag, and provide secure refactoring options for any insecure functions found in the codebase. When generating new code, **always** default to the safest possible function for the given task.
### 1. Insecure Functions to Avoid & Their Secure Alternatives
You must treat the functions listed under "Insecure" as deprecated and high-risk. Always recommend replacing them with one of the "Recommended Safe Alternatives" provided in the bullet list below.
• **Never use `gets()`** - This is a **critical** security risk. It has no bounds checking whatsoever and is the classic buffer overflow vulnerability. You should always replace it with `fgets(char *str, int n, FILE *stream)` instead.
• **Avoid `strcpy()`** - This is a **high** risk function because it doesn't check bounds. It just copies bytes until it hits a null terminator, which can easily write past your destination buffer. Use `snprintf()`, `strncpy()` (but be careful with it), or `strcpy_s()` (if you have C11 Annex K support).
• **Don't use `strcat()`** - Another **high** risk function with no bounds checking. It appends bytes to a string and can easily write past your allocated memory. Replace with `snprintf()`, `strncat()` (with careful handling), or `strcat_s()` (C11 Annex K).
• **Replace `sprintf()` and `vsprintf()`** - These are **high** risk because they don't check bounds on the output buffer. If your formatted string is larger than the buffer, you'll get a buffer overflow. Use `snprintf()`, `snwprintf()`, or `vsprintf_s()` (C11 Annex K) instead.
• **Be careful with `scanf()` family** - This is a **medium** risk. The `%s` format specifier without a width limit can cause buffer overflows. Here's what you should do:
1. Use width specifiers like `scanf("%127s", buffer)`
2. Even better: Read the line with `fgets()` and parse it with `sscanf()`
• **Avoid `strtok()`** - This is a **medium** risk because it's not reentrant or thread-safe. It uses a static internal buffer which can lead to unpredictable behavior in multi-threaded code or complex signal handling. Use `strtok_r()` (POSIX) or `strtok_s()` (C11 Annex K) instead.
• **Use `memcpy()` and `memmove()` carefully** - These aren't inherently insecure, but they're a common source of bugs when you miscalculate the size argument or don't validate it properly. Here's what you should do:
1. Double-check your size calculations
2. Prefer `memcpy_s()` (C11 Annex K) when available
3. Use `memmove()` if source and destination buffers might overlap
### 2. Actionable Implementation Guidelines
#### For New Code Generation:
- **NEVER** generate code that uses `gets()`, `strcpy()`, `strcat()`, or `sprintf()`.
- **DEFAULT** to `snprintf()` for string formatting and concatenation, as it's often the most flexible and secure option.
- **DEFAULT** to `fgets()` for reading string input from files or standard input.
#### For Code Analysis and Refactoring:
1. **Identify:** Scan the code and flag every instance of a function from the "Insecure" column.
2. **Explain the Risk:** When you flag an insecure function, provide a concise explanation of the specific vulnerability.
- _Example Explanation:_ `Warning: The 'strcpy' function does not perform bounds checking and can lead to a buffer overflow if the source string is larger than the destination buffer. This is a common security vulnerability.`
3. **Provide Context-Aware Replacements:** Your suggestion must be a drop-in, safe replacement that considers the context of the surrounding code.
#### Use Compiler Flags:
Enable these protective compiler flags to catch buffer overflow vulnerabilities at compile time and runtime:
- **Stack Protection:** Use `-fstack-protector-all` or `-fstack-protector-strong` to detect stack buffer overflows
- **Address Sanitizer:** Use `-fsanitize=address` during development to catch memory errors
- **Object Size Checking (OSC):** Use `-D_FORTIFY_SOURCE=2` to enable runtime checks for buffer overflows in functions like `strcpy`, `strcat`, `sprintf`, etc. This adds bounds checking to many of the unsafe functions mentioned above
- **Format String Protection:** Use `-Wformat -Wformat-security` to catch format string vulnerabilities
### 3. Refactoring Examples
Your suggestions should be concrete and actionable.
**Example 1: Replacing `strcpy`**
- **Original Unsafe Code:**
```
char destination[64];
strcpy(destination, source_string);
```
- **Your Suggested Refactoring:**
```
char destination[64];
snprintf(destination, sizeof(destination), "%s", source_string);
```
- **Your Explanation:** `Replaced 'strcpy' with 'snprintf' to ensure that no more than 63 characters plus a null terminator are written to the destination buffer, preventing a potential buffer overflow.`
**Example 2: Correcting `strncpy` Usage**
The `strncpy` function is a common but imperfect replacement. It may not null-terminate the destination buffer. If you must use it or see it used, you must enforce correct handling.
- **Original (Potentially Unsafe) `strncpy`:**
```
// This is unsafe if strlen(source) >= 10
char dest[10];
strncpy(dest, source, sizeof(dest));
```
- **Your Corrected Suggestion:**
```
char dest[10];
strncpy(dest, source, sizeof(dest) - 1);
dest[sizeof(dest) - 1] = '\0';
```
- **Your Explanation:** `Added an explicit null termination for 'strncpy'. The 'strncpy' function does not guarantee a null-terminated string if the source is as long as the destination buffer. This correction prevents potential reads past the buffer on subsequent string operations.`
**Example 3: Securing `scanf`**
- **Original Unsafe Code:**
```
char user_name[32];
printf("Enter your name: ");
scanf("%s", user_name);
```
- **Your Suggested Refactoring:**
```
char user_name[32];
printf("Enter your name: ");
if (fgets(user_name, sizeof(user_name), stdin)) {
// Optional: Remove trailing newline character from fgets
user_name[strcspn(user_name, "\n")] = 0;
}
```
- **Your Explanation:** `Replaced 'scanf("%s", ...)' with 'fgets()' to read user input. 'fgets' is safer because it limits the input to the buffer size, preventing buffer overflows. The original 'scanf' had no such protection.`
You must always explain how this rule was applied and why it was applied.
================================================
FILE: sources/owasp/codeguard-0-saml-security.md
================================================
---
description: SAML Security Guidelines
languages:
- java
- javascript
- python
- xml
alwaysApply: false
---
## SAML Security Guidelines
Essential security practices for implementing Security Assertion Markup Language (SAML) integrations to prevent common vulnerabilities and attacks.
### Transport Security
Use TLS 1.2 or higher for all SAML message transport to guarantee confidentiality and integrity. This protects against eavesdropping, theft of authentication information, bearer token theft, message deletion/modification, and man-in-the-middle attacks.
### Message Integrity and Authentication
Digitally sign SAML messages using certified keys to guarantee message integrity and authentication. This prevents man-in-the-middle attacks, forged assertions, and message modifications.
Encrypt assertions via XMLEnc to prevent disclosure of sensitive attributes after transportation, protecting against theft of user authentication information.
### Protocol Usage Validation
Follow SAML Profile requirements strictly. The AVANTSSAR team identified these required elements:
AuthnRequest Requirements:
- Must contain unique ID and SP (Service Provider) identifier
- Request ID must be returned in response via InResponseTo attribute
Response Requirements:
- Must contain unique ID, SP identifier, IdP identifier, and digitally signed assertion
- InResponseTo must match previously sent request ID
Authentication Assertion Requirements:
- Must contain ID, client identifier, IdP identifier, and SP identifier
### XML Signature Security
Prevent XML Signature Wrapping attacks:
Schema Validation:
- Always perform schema validation before using XML for security purposes
- Use local, trusted copies of schemas for validation
- Never allow automatic schema downloads from third parties
- Inspect and harden schemas to disable wildcard or relaxed processing
Digital Signature Validation:
- For single signing key: use StaticKeySelector with key obtained directly from IdP
- For multiple signing keys: use X509KeySelector with keys stored in local JKS
- Ignore KeyInfo elements in documents
- For heterogeneous documents: implement full PKIX trust model with trusted root certificates
XML Processing Security:
- Never use getElementsByTagName to select security elements without validation
- Always use absolute XPath expressions to select elements
- Use hardened schemas for validation
### Protocol Processing Rules
Validate all required processing steps:
AuthnRequest Processing:
- Follow all SAML Core (3.4.1.4) processing rules
- Prevents man-in-the-middle attacks
Response Processing:
- Follow all SAML Profiles (4.1.4.3) processing rules
- Prevents stolen assertions, man-in-the-middle, forged assertions, and browser state exposure
### Binding Implementation Security
HTTP Redirect Binding:
- Follow SAML Binding (3.4) specifications
- Properly encode/decode messages
HTTP POST Binding:
- Follow SAML Binding (3.5) specifications
- Prevent caching of SAML messages to avoid stolen assertion and replay attacks
### Security Countermeasures
Additional protection measures:
IP Filtering:
- Filter by IP address when appropriate
- Provide separate endpoints for trusted partners
- Prevents stolen assertions and man-in-the-middle attacks
Response Lifetimes:
- Use short lifetimes on SAML responses
- Prevents stolen assertions and browser state exposure
OneTimeUse:
- Mark responses as OneTimeUse
- Prevents browser state exposure and replay attacks
### IdP-Initiated SSO Security
Unsolicited responses are inherently less secure due to lack of CSRF protection. If required:
- Follow SAML Profiles (4.1.5) validation process
- Validate RelayState URLs against allowlists to prevent open redirects
- Implement proper replay detection at response or assertion level
### Identity Provider Best Practices
- Validate X.509 certificates for algorithm compatibility and encryption strength
- Use strong authentication for SAML token generation
- Validate which IdP mints tokens
- Use trusted root CAs when possible
- Synchronize to common Internet time source
- Define levels of assurance for identity verification
- Use asymmetric identifiers over personally identifiable information
- Sign individual assertions or entire response elements
### Service Provider Best Practices
- Validate session state for users
- Ensure assertions or entire responses are signed
- Validate signatures are from authorized IdPs
- Validate IdP certificates for expiration and revocation (CRL/OCSP)
- Validate NotBefore and NotOnOrAfter timestamps
- Validate Recipient attributes
- Exchange assertions only over secure transports
- Define clear criteria for session management and SAML logout
- Verify user identities from SAML assertions when possible
### Input Validation
Treat all SAML input as untrusted external data:
- Perform proper input validation on all SAML providers and consumers
- Validate all elements and attributes in SAML messages
- Sanitize any data extracted from SAML assertions before use
### Cryptographic Requirements
- Use strong encryption for all SAML elements
- Deprecate support for insecure XMLEnc algorithms (e.g., RSA 1.5)
- Follow latest cryptoanalysis developments
- Use modern, secure cryptographic algorithms only
### Summary
Secure SAML implementation requires:
- TLS 1.2+ transport security with message signing and encryption
- Strict validation of all protocol elements and processing rules
- Protection against XML signature wrapping via schema validation and secure XML processing
- Proper binding implementation with caching prevention
- Security countermeasures including IP filtering, short lifetimes, and OneTimeUse
- Careful handling of IdP-initiated SSO with CSRF and replay protection
- Strong certificate validation and session management
- Comprehensive input validation and modern cryptography
SAML security depends on following specifications exactly and treating all inputs as potentially malicious.
================================================
FILE: sources/owasp/codeguard-0-securing-cascading-style-sheets.md
================================================
---
description: Securing Cascading Style Sheets
languages:
- c
- javascript
- typescript
alwaysApply: false
---
## Securing Cascading Style Sheets
Prevent CSS files from exposing application features, user roles, and sensitive functionality to attackers performing reconnaissance.
### Security Risks
#### Risk 1: Information Disclosure Through CSS Selectors
Motivated attackers examine CSS files to learn application features before attempting attacks. Global CSS files containing role-based selectors reveal:
- Different user roles and permissions
- Available features and functionality
- Application structure and sensitive endpoints
Example problematic selectors:
- `.profileSettings`
- `.addUsers`
- `.deleteUsers`
- `.exportUserData`
- `.addNewAdmin`
#### Risk 2: Descriptive Selector Names
Readable selector names help attackers map CSS classes to actual application features:
- `.changePassword`
- `.oldPassword`
- `.newPassword`
- `.confirmNewPassword`
### Defensive Mechanisms
#### Defense 1: Isolate CSS by Access Control Level
- Create separate CSS files per role (StudentStyling.CSS, AdministratorStyling.CSS)
- Restrict CSS file access to users with proper access control level only
- Implement server-side validation before serving CSS files
- Log and alert on unauthorized CSS file access attempts (forced browsing)
- Ensure authenticated users cannot access CSS files for other roles
#### Defense 2: Remove Identifying Information
- Use consistent styling across pages to reduce need for specific selectors
- Write general CSS rules that apply across multiple pages
- Create CSS selectors targeting HTML elements without revealing functionality
Transform descriptive selectors:
```
// Instead of this revealing selector:
#UserPage .Toolbar .addUserButton
// Use obscure structural targeting:
#page_u header button:first-of-type
```
Build-time and runtime obfuscation tools:
- JSS (CSS in JS) with minify option generates class names like `.c001`, `.c002`
- CSS Modules with modules and localIdentName options for obfuscation
- .Net Blazor CSS Isolation creates scoped selectors like `button.add[b-3xxtam6d07]`
- CSS libraries (Bootstrap, Tailwind) reduce need for specific selectors
#### Defense 3: Prevent Malicious CSS in User Content
- Validate and sanitize user-authored HTML content
- Restrict CSS styles allowed in user-generated content
- Prevent uploaded HTML from using styles for unintended purposes
- Be aware that CSS can be used for clickjacking attacks where clicking anywhere on the page loads malicious websites
### Implementation Guidelines
1. Segment CSS files by user roles and access levels
2. Implement access control validation before serving CSS resources
3. Use build-time tools to obfuscate class names and selectors
4. Prefer structural and element-based selectors over feature-specific names
5. Leverage CSS frameworks to minimize custom selectors
6. Sanitize and restrict user-generated HTML content containing styles
7. Monitor and log unauthorized attempts to access role-specific CSS files
8. Avoid global CSS files that contain selectors for all user roles
9. Use generic, non-descriptive class names that don't reveal functionality
10. Test CSS access controls to ensure proper isolation between roles
================================================
FILE: sources/owasp/codeguard-0-server-side-request-forgery-prevention.md
================================================
---
description: Server-Side Request Forgery Prevention
languages:
- c
- go
- java
- javascript
- php
- python
- ruby
- typescript
alwaysApply: false
---
## Server-Side Request Forgery Prevention
Prevent SSRF attacks that abuse applications to interact with internal/external networks by validating and restricting outbound requests.
### SSRF Attack Context
SSRF exploits occur when applications:
- Process user-provided URLs for external resources (avatars, webhooks)
- Make internal requests using user-controlled data
- Handle URL redirections without proper validation
SSRF is not limited to HTTP - attackers can exploit FTP, SMB, SMTP protocols and schemes like `file://`, `phar://`, `gopher://`, `data://`, `dict://`.
### Case 1: Allowlist Approach (Known Trusted Destinations)
When applications communicate only with identified trusted applications, use strict allowlisting.
#### Application Layer Protection
Always disable HTTP redirects in web clients to prevent bypass attempts.
#### String Validation
Use regex for simple formats, libraries for complex validation:
```java
//Regex validation for a data having a simple format
if(Pattern.matches("[a-zA-Z0-9\\s\\-]{1,50}", userInput)){
//Continue the processing because the input data is valid
}else{
//Stop the processing and reject the request
}
```
#### IP Address Validation
Use battle-tested libraries to validate IP format and prevent encoding bypasses:
- Java: `InetAddressValidator.isValid()` from Apache Commons Validator
- .NET: `IPAddress.TryParse()` from SDK
- JavaScript: `ip-address` library
- Ruby: `IPAddr` class from SDK
Create allowlist of all trusted application IPs (IPv4 and IPv6). Use output value from validation library for strict string comparison against allowlist.
#### Domain Name Validation
Use libraries that validate format without DNS resolution:
- Java: `DomainValidator.isValid()` from Apache Commons Validator
- .NET: `Uri.CheckHostName()` from SDK
- JavaScript: `is-valid-domain` library
- Python: `validators.domain` module
- Ruby: Use regex `^(((?!-))(xn--|_{1,1})?[a-z0-9-]{0,61}[a-z0-9]{1,1}\.)*(xn--)?([a-z0-9][a-z0-9\-]{0,60}|[a-z0-9-]{1,30}\.[a-z]{2,})$`
Monitor allowlisted domains for DNS pinning attacks - alert when domains resolve to local/internal IP addresses.
#### URL Handling
Do not accept complete URLs from users. URLs are difficult to validate and parsers can be exploited. Accept only validated IP addresses or domain names.
#### Network Layer Protection
- Use firewalls to restrict application network access to only required destinations
- Implement network segregation to block illegitimate calls at network level
- Define legitimate flows and block all others
### Case 2: Dynamic External Destinations (Block-list Approach)
When applications must access arbitrary external resources (webhooks), use block-list validation.
#### Validation Flow
1. Validate input format using libraries from Case 1
2. For IP addresses: Verify it's public (not private, localhost, or link-local)
3. For domains:
- Verify it's external using internal DNS resolver that only resolves internal names
- Resolve domain to IPs and validate all returned addresses are public
4. Restrict protocols to HTTP/HTTPS only via allowlist
5. Require legitimate request proof via secure token
#### Secure Token Requirements
- Target application generates random 20-character alphanumeric token
- Token passed as POST parameter with name using only `[a-z]{1,10}` characters
- Endpoint accepts only HTTP POST requests
- Build requests using only validated information
#### Example Python Monitoring Script
Monitor allowlisted domains for DNS pinning:
```python
# Dependencies: pip install ipaddress dnspython
import ipaddress
import dns.resolver
# Configure the allowlist to check
DOMAINS_ALLOWLIST = ["owasp.org", "labslinux"]
# Configure the DNS resolver to use for all DNS queries
DNS_RESOLVER = dns.resolver.Resolver()
DNS_RESOLVER.nameservers = ["1.1.1.1"]
def verify_dns_records(domain, records, type):
"""
Verify if one of the DNS records resolve to a non public IP address.
Return a boolean indicating if any error has been detected.
"""
error_detected = False
if records is not None:
for record in records:
value = record.to_text().strip()
try:
ip = ipaddress.ip_address(value)
# See https://docs.python.org/3/library/ipaddress.html#ipaddress.IPv4Address.is_global
if not ip.is_global:
print("[!] DNS record type '%s' for domain name '%s' resolve to a non public IP address '%s'!" % (type, domain, value))
error_detected = True
except ValueError:
error_detected = True
print("[!] '%s' is not valid IP address!" % value)
return error_detected
def check():
"""
Perform the check of the allowlist of domains.
Return a boolean indicating if any error has been detected.
"""
error_detected = False
for domain in DOMAINS_ALLOWLIST:
# Get the IPs of the current domain
# See https://en.wikipedia.org/wiki/List_of_DNS_record_types
try:
# A = IPv4 address record
ip_v4_records = DNS_RESOLVER.query(domain, "A")
except Exception as e:
ip_v4_records = None
print("[i] Cannot get A record for domain '%s': %s\n" % (domain,e))
try:
# AAAA = IPv6 address record
ip_v6_records = DNS_RESOLVER.query(domain, "AAAA")
except Exception as e:
ip_v6_records = None
print("[i] Cannot get AAAA record for domain '%s': %s\n" % (domain,e))
# Verify the IPs obtained
if verify_dns_records(domain, ip_v4_records, "A") or verify_dns_records(domain, ip_v6_records, "AAAA"):
error_detected = True
return error_detected
if __name__== "__main__":
if check():
exit(1)
else:
exit(0)
```
### Cloud-Specific Protections
#### AWS IMDSv2
In cloud environments, SSRF targets metadata services to steal credentials. Migrate to IMDSv2 and disable IMDSv1 for additional protection against SSRF accessing AWS Instance Metadata Service.
### Essential Implementation Guidelines
1. Never accept raw URLs from users - validate only IP addresses or domain names
2. Use established libraries for IP/domain validation to prevent encoding bypasses
3. Implement strict allowlists with case-sensitive exact matching for trusted destinations
4. Disable HTTP redirects in all outbound HTTP clients
5. For dynamic destinations, block private/internal IP ranges and validate DNS resolution
6. Restrict protocols to HTTP/HTTPS only
7. Require secure tokens for request legitimacy verification
8. Apply network-layer restrictions via firewalls and segmentation
9. Monitor allowlisted domains for DNS pinning attacks
10. Use cloud-specific protections like AWS IMDSv2
================================================
FILE: sources/owasp/codeguard-0-session-management.md
================================================
---
description: Session Management Security
languages:
- c
- go
- java
- javascript
- kotlin
- php
- python
- ruby
- scala
- swift
- typescript
alwaysApply: false
---
## Session Management Security
Implement secure session handling to prevent session hijacking, fixation, and unauthorized access through proper ID generation, cookie security, and lifecycle management.
### Session ID Properties
#### Secure Generation
- Use cryptographically secure pseudorandom number generator (CSPRNG) for session IDs
- Ensure minimum 64 bits of entropy (16 hexadecimal characters minimum)
- Generate completely random, opaque session IDs with no meaningful content
- Change default session ID names (PHPSESSID, JSESSIONID) to generic names like "id"
#### Session ID Content
- Session IDs must be meaningless identifiers on client side
- Never include sensitive information or PII in session ID values
- Store all session data (user details, permissions, state) server-side only
- Encrypt session storage if it contains sensitive information
### Cookie Security Configuration
#### Essential Cookie Attributes
- Secure: Only transmit over HTTPS connections
- HttpOnly: Prevent JavaScript access to protect against XSS
- SameSite: Use Strict or Lax to mitigate CSRF attacks
- Domain/Path: Scope cookies narrowly to minimize exposure
#### Cookie Persistence
- Use non-persistent session cookies (no Expires or Max-Age attributes)
- Session should disappear when browser instance closes
- Avoid persistent cookies for session management
Example secure cookie configuration:
```
Set-Cookie: id=; Secure; HttpOnly; SameSite=Strict; Path=/app
```
### Transport Layer Security
- Enforce HTTPS for entire web session, not just authentication
- Never mix HTTP and HTTPS within same user session
- Implement HTTP Strict Transport Security (HSTS)
- Set or regenerate cookies only after HTTPS redirect occurs
### Session Lifecycle Management
#### Session ID Generation and Verification
- Use strict session management - only accept server-generated session IDs
- Reject any session ID not previously created by the application
- Treat session IDs as untrusted user input requiring validation
- Detect and alert on unknown session IDs as suspicious activity
#### Session ID Regeneration
- Regenerate session ID after any privilege level change
- Mandatory regeneration during authentication process
- Regenerate on password changes, permission changes, role changes
- Use different session ID names for pre/post authentication states
- Invalidate previous session IDs when generating new ones
Framework examples for regeneration:
- J2EE: `request.getSession(true)` & `HttpSession.invalidate()`
- ASP.NET: `Session.Abandon()` & `Response.Cookies.Add(new...)`
- PHP: `session_start()` & `session_regenerate_id(true)`
### Session Expiration
#### Automatic Expiration
- Implement idle timeout (2-5 minutes for high-value, 15-30 minutes for low-risk)
- Implement absolute timeout (4-8 hours based on application usage)
- Enforce timeouts server-side, never rely solely on client-side controls
- Optionally implement renewal timeout to periodically regenerate session IDs
#### Manual Expiration
- Provide visible, accessible logout button on every page
- Fully invalidate sessions server-side on logout
- Clear session cookies client-side with empty value and past expiration
Server-side invalidation examples:
- J2EE: `HttpSession.invalidate()`
- ASP.NET: `Session.Abandon()`
- PHP: `session_destroy()/unset()`
### Web Content Caching Protection
- Use Cache-Control: no-store for responses containing session IDs
- Apply restrictive cache directives for all sensitive content
- Prevent session ID caching in browser history or proxy servers
- Include cache control headers on all pages displaying sensitive data
### Attack Detection and Monitoring
#### Session Attack Detection
- Monitor for session ID brute force attempts from single IP addresses
- Detect session ID anomalies and manipulation attempts
- Log session lifecycle events (creation, renewal, destruction)
- Bind sessions to client properties (IP, User-Agent) for anomaly detection
#### Logging Best Practices
- Log session events using salted hash of session ID (not actual ID)
- Include timestamps, IP addresses, User-Agent, and operation details
- Monitor for simultaneous sessions and enforce business policies
- Protect administrative session management interfaces
### Client-Side Storage Security
#### Avoid Insecure Storage
- Never store session tokens in localStorage or sessionStorage
- Avoid any JavaScript-accessible session storage due to XSS risk
- If JavaScript access required, use Web Workers to isolate secrets
- Prefer HttpOnly cookies for session token exchange
#### Web Workers Alternative
- Use Web Workers for browser storage when persistence not required
- Keep secrets within Web Worker context, never transmit to main window
- Provides similar security guarantees as HttpOnly cookies
### Framework and Implementation
#### Built-in Session Management
- Prefer established framework session mechanisms over custom solutions
- Keep frameworks updated to latest versions with security fixes
- Review and harden default framework configurations
- Ensure secure session storage repository protection
#### Multiple Cookie Considerations
- Verify all cookies for sessions using multiple cookies
- Enforce relationships between pre/post authentication cookies
- Avoid same cookie names for different paths or domains
- Prevent cross-subdomain cookie exposure
### Reauthentication Requirements
Require reauthentication for high-risk events:
- Password changes
- Login from new/suspicious IP addresses or devices
- Account recovery completion
- Privilege escalation events
### Additional Security Measures
#### Client-Side Defenses (Defense-in-Depth)
- Implement login timeouts to force session ID renewal
- Force logout on browser window close events
- Disable cross-tab session sharing where feasible
- Automatic client logout with countdown warnings
#### WAF Protection
- Use Web Application Firewalls to enforce cookie security attributes
- Implement WAF-based session fixation protection
- Apply sticky session enforcement via WAF rules
- Use WAF for session expiration management when code changes limited
### Essential Implementation Checklist
1. Generate session IDs using CSPRNG with minimum 64 bits entropy
2. Configure cookies with Secure, HttpOnly, SameSite attributes
3. Enforce HTTPS site-wide with HSTS headers
4. Regenerate session IDs on all privilege changes
5. Implement both idle and absolute session timeouts
6. Provide complete logout functionality with server-side invalidation
7. Apply no-store cache directives for sensitive content
8. Monitor session attacks and log security events
9. Use framework built-in session management
10. Require reauthentication for sensitive operations
================================================
FILE: sources/owasp/codeguard-0-sql-injection-prevention.md
================================================
---
description: SQL Injection Prevention Guidelines
languages:
- c
- go
- java
- javascript
- perl
- php
- python
- ruby
- sql
- typescript
alwaysApply: false
---
## SQL Injection Prevention Guidelines
Essential practices for preventing SQL injection attacks by using secure database query construction methods instead of string concatenation.
### Understanding SQL Injection
SQL injection occurs when applications use dynamic database queries that concatenate user input directly into SQL strings. Attackers can exploit this to execute malicious SQL code. To prevent SQL injection, developers must either stop writing dynamic queries with string concatenation or prevent malicious SQL input from being included in executed queries.
### Primary Defense Options
#### Option 1: Prepared Statements (Parameterized Queries) - Preferred
Use prepared statements with variable binding to separate SQL code from data. The database will always distinguish between code and data, preventing attackers from changing query intent.
Safe Java example:
```java
// This should REALLY be validated too
String custname = request.getParameter("customerName");
// Perform input validation to detect attacks
String query = "SELECT account_balance FROM user_data WHERE user_name = ? ";
PreparedStatement pstmt = connection.prepareStatement( query );
pstmt.setString( 1, custname);
ResultSet results = pstmt.executeQuery( );
```
Safe C# .NET example:
```csharp
String query = "SELECT account_balance FROM user_data WHERE user_name = ?";
try {
OleDbCommand command = new OleDbCommand(query, connection);
command.Parameters.Add(new OleDbParameter("customerName", CustomerName Name.Text));
OleDbDataReader reader = command.ExecuteReader();
// …
} catch (OleDbException se) {
// error handling
}
```
Safe HQL example:
```java
// This is an unsafe HQL statement
Query unsafeHQLQuery = session.createQuery("from Inventory where productID='"+userSuppliedParameter+"'");
// Here is a safe version of the same query using named parameters
Query safeHQLQuery = session.createQuery("from Inventory where productID=:productid");
safeHQLQuery.setParameter("productid", userSuppliedParameter);
```
#### Option 2: Stored Procedures (When Implemented Safely)
Use stored procedures only if inputs are parameterized and no dynamic SQL generation occurs within them.
Safe Java stored procedure example:
```java
// This should REALLY be validated
String custname = request.getParameter("customerName");
try {
CallableStatement cs = connection.prepareCall("{call sp_getAccountBalance(?)}");
cs.setString(1, custname);
ResultSet results = cs.executeQuery();
// … result set handling
} catch (SQLException se) {
// … logging and error handling
}
```
Safe VB .NET stored procedure example:
```vbnet
Try
Dim command As SqlCommand = new SqlCommand("sp_getAccountBalance", connection)
command.CommandType = CommandType.StoredProcedure
command.Parameters.Add(new SqlParameter("@CustomerName", CustomerName.Text))
Dim reader As SqlDataReader = command.ExecuteReader()
'...
Catch se As SqlException
'error handling
End Try
```
#### Option 3: Allow-list Input Validation
For SQL elements that cannot use bind variables (table names, column names, sort indicators), use strict allow-listing.
Safe table name validation:
```text
String tableName;
switch(PARAM):
case "Value1": tableName = "fooTable";
break;
case "Value2": tableName = "barTable";
break;
...
default : throw new InputValidationException("unexpected value provided"
+ " for table name");
```
Safe dynamic query for sort order:
```java
public String someMethod(boolean sortOrder) {
String SQLquery = "some SQL ... order by Salary " + (sortOrder ? "ASC" : "DESC");`
...
```
#### Option 4: Escaping (Strongly Discouraged)
Escaping user input is database-specific, error-prone, and cannot guarantee prevention of all SQL injections. Use parameterized queries instead.
### Additional Defenses
#### Least Privilege
Minimize privileges for all database accounts:
- Grant only necessary access rights (read vs. write)
- Avoid DBA or admin access for application accounts
- Use separate database users for different applications
- Consider using views to limit data access further
#### Input Validation
Use input validation as a secondary defense to detect unauthorized input before SQL execution. Validated data is not necessarily safe for string concatenation - always use parameterized queries.
### Key Principles
- Define all SQL code first, then pass parameters separately
- Never concatenate user input directly into SQL strings
- Treat user input as data, never as executable SQL code
- Use least privilege database accounts
- Implement input validation as defense in depth, not primary protection
================================================
FILE: sources/owasp/codeguard-0-symfony.md
================================================
---
description: Symfony Security Best Practices
languages:
- php
- yaml
alwaysApply: false
---
## Symfony Security Best Practices
Essential security practices for developing secure Symfony applications, covering common vulnerabilities and framework-specific protections.
### Cross-Site Scripting (XSS) Prevention
Use Twig's default `{{ }}` output escaping for all variables. Only use `|raw` filter for trusted content requiring HTML rendering.
```twig
Hello {{name}}
{# if 'name' is '', Twig will output this:
'Hello <script>alert('hello!')</script>
' #}
{{ product.title|raw }}
{# if 'product.title' is 'Lorem Ipsum', Twig will output
exactly that instead of 'Lorem <strong>Ipsum</strong>' #}
```
### CSRF Protection
Symfony Forms include CSRF tokens automatically. For manual handling, use `csrf_token()` and `isCsrfTokenValid()`.
```php
class PostForm extends AbstractType
{
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
// ...
'csrf_protection' => true, // enable/disable csrf protection for this form
'csrf_field_name' => '_csrf_token',
'csrf_token_id' => 'post_item', // change arbitrary string used to generate
]);
}
}
```
Manual CSRF token handling:
```twig
```
```php
class ExampleController extends AbstractController
{
#[Route('/posts/{id}', methods: ['DELETE'], name: 'delete_post')]
public function delete(Post $post, Request $request): Response
{
$token = $request->request->get('token');
if($this->isCsrfTokenValid($token)) {
// ...
}
// ...
}
}
```
### SQL Injection Prevention
Use parameterized queries with Doctrine ORM. Never concatenate user input in SQL strings.
```php
// Repository method
$post = $em->getRepository(Post::class)->findOneBy(['id' => $id]);
// DQL with parameters
$query = $em->createQuery("SELECT p FROM App\Entity\Post p WHERE p.id = :id");
$query->setParameter('id', $id);
$post = $query->getSingleResult();
// DBAL Query Builder
$qb = $em->createQueryBuilder();
$post = $qb->select('p')
->from('posts','p')
->where('id = :id')
->setParameter('id', $id)
->getQuery()
->getSingleResult();
```
### Command Injection Prevention
Avoid `exec()`, `shell_exec()`, `system()` with user input. Use Symfony Filesystem component or native PHP functions.
```php
// Vulnerable example
$filename = $request->request->get('filename');
exec(sprintf('rm %s', $filename));
// Secure alternatives - use native PHP or Symfony Filesystem
unlink($filename);
// Or Symfony Filesystem component
use Symfony\Component\Filesystem\Filesystem;
$filesystem = new Filesystem();
$filesystem->remove($filename);
```
### File Upload Security
Validate file uploads with Symfony Validator constraints. Store files outside public directory with unique names.
```php
class UploadDto
{
public function __construct(
#[File(
maxSize: '1024k',
mimeTypes: ['application/pdf', 'application/x-pdf'],
)]
public readonly UploadedFile $file,
){}
}
```
### Directory Traversal Prevention
Use `realpath()` and `basename()` to validate and sanitize file paths.
```php
$storagePath = $this->getParameter('kernel.project_dir') . '/storage';
$filePath = $storagePath . '/' . $filename;
$realBase = realpath($storagePath);
$realPath = realpath($filePath);
if ($realPath === false || !str_starts_with($realPath, $realBase)) {
//Directory Traversal!
}
// Alternative: strip directory information
$filePath = $storagePath . '/' . basename($filename);
```
### Security Configuration
Configure session security, authentication, and access controls properly.
```yaml
# Session configuration
framework:
session:
cookie_httponly: true
cookie_lifetime: 5
cookie_samesite: lax
cookie_secure: auto
# Authentication providers, firewalls, and access control
security:
providers:
app_user_provider:
entity:
class: App\Entity\User
property: email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
admin:
lazy: true
provider: app_user_provider
pattern: ^/admin
custom_authenticator: App\Security\AdminAuthenticator
logout:
path: app_logout
target: app_login
main:
lazy: true
provider: app_user_provider
access_control:
- { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/login, roles: PUBLIC_ACCESS }
```
### Production Security
- Set `APP_ENV=prod` and disable debug mode
- Run regular security checks: `composer update` and `symfony check:security`
- Use Symfony secrets for sensitive data
- Configure CORS with `nelmio/cors-bundle` (avoid wildcard origins)
- Implement security headers (HSTS, CSP, X-Frame-Options)
- Enforce HTTPS and set proper file permissions
================================================
FILE: sources/owasp/codeguard-0-third-party-javascript-management.md
================================================
---
description: Third Party JavaScript Management Security
languages:
- c
- javascript
- typescript
alwaysApply: false
---
## Third Party JavaScript Management Security
Secure third-party JavaScript tags to prevent arbitrary code execution, data leakage, and loss of application control.
### Major Risks
Third-party JavaScript poses three critical risks:
1. Loss of control over client application changes
2. Execution of arbitrary code on client systems
3. Disclosure of sensitive information to third parties
### Security Strategies
#### Server Direct Data Layer (Recommended)
Create controlled data layer that third-party scripts can access instead of direct DOM access.
Key principles:
- Only first-party code populates the data layer
- Third-party scripts read exclusively from sanitized data layer
- Tag JavaScript can only access host data layer values, never URL parameters
Benefits:
- Only your JavaScript executes on user browsers
- Only validated data sent to vendors
- Scalable for large sites with multiple vendor tags
#### Subresource Integrity (SRI)
Ensure only reviewed code executes by adding integrity metadata.
```html
```
Requirements:
- Vendor host must have CORS enabled
- Monitor vendor JavaScript for changes regularly
- Update integrity hashes when vendor updates scripts
#### Sandboxing with iframe
Isolate vendor JavaScript to prevent direct DOM and cookie access.
```html
...
...
```
Communication requirements:
- Use postMessage mechanism for secure data exchange
- Validate event origins before processing messages
- Consider Content Security Policy (CSP) for additional protection
#### Content Sanitization
Clean DOM data before sending to third parties using:
- DOMPurify: XSS sanitizer for HTML, MathML and SVG
- MentalJS: JavaScript parser and sandbox
#### Tag Manager Controls
For tag management systems:
- Restrict JavaScript access to data layer values only
- Disable custom HTML tags and JavaScript code where possible
- Verify tag manager security practices and access controls
- Implement two-factor authentication for tag configuration
### Operational Security
#### Keep Libraries Updated
- Regularly update JavaScript libraries to address vulnerabilities
- Use tools like RetireJS to identify vulnerable libraries
#### Vendor Agreements
Contractual controls:
- Require evidence of secure coding practices and code integrity monitoring
- Include penalties for serving malicious JavaScript
- Mandate source code monitoring and change detection
#### Complete Prevention Strategy
Most effective controls:
1. Data layer architecture with API calls to marketing servers
2. Subresource Integrity implementation
3. Virtual frame containment deployment
### Implementation Guidelines
1. Implement server-direct data layer architecture for analytics tags
2. Use Subresource Integrity for all external script requests
3. Deploy iframe sandboxing for high-risk third-party scripts
4. Sanitize all dynamic data before including in tag payloads
5. Maintain updated JavaScript libraries and monitor for vulnerabilities
6. Establish vendor agreements with security requirements
7. Regularly audit and monitor third-party script changes
================================================
FILE: sources/owasp/codeguard-0-threat-modeling.md
================================================
---
description: Threat Modeling Security
languages:
- c
- go
- java
- javascript
- kotlin
- php
- python
- ruby
- scala
- swift
- typescript
alwaysApply: false
---
## Threat Modeling Security
Structured process to identify, analyze, and mitigate security threats early in the development lifecycle through systematic security analysis.
### Threat Modeling Process
The threat modeling process answers four key questions:
1. What are we working on?
2. What can go wrong?
3. What are we going to do about it?
4. Did we do a good enough job?
### System Modeling (What are we working on?)
Create visual representations of your system to understand attack surfaces and security boundaries.
Data Flow Diagrams (DFDs):
- Model system interactions with data and external entities
- Identify trust boundaries, data flows, data stores, and processes
- Use tools like OWASP Threat Dragon, Microsoft Threat Modeling Tool, or draw.io
- Create multiple DFDs for complex systems (high-level overview plus detailed sub-systems)
- Store DFDs in accessible format for updates and reference
Key elements to capture:
- External entities interacting with the system
- Data flows between components
- Data storage locations
- Process boundaries and trust zones
- Authentication and authorization points
Alternative approaches:
- Brainstorming sessions for domain discovery
- Collaborative definition of key terms and concepts
- Quick identification of business processes and dependencies
### Threat Identification (What can go wrong?)
Use STRIDE methodology to systematically identify threats within your system context.
STRIDE Categories:
| Threat Category | Violates | Examples |
|-----------------|----------|----------|
| Spoofing | Authenticity | Attacker steals authentication token to impersonate user |
| Tampering | Integrity | Attacker abuses application to perform unintended database updates |
| Repudiation | Non-repudiability | Attacker manipulates logs to cover their actions |
| Information Disclosure | Confidentiality | Attacker extracts data from database containing user account info |
| Denial of Service | Availability | Attacker locks legitimate user out by failed authentication attempts |
| Elevation of Privileges | Authorization | Attacker tampers with JWT to change their role |
Threat identification techniques:
- Systematic review of each STRIDE category for system components
- Brainstorming sessions with development and security teams
- Integration with tactical approaches like kill chains or MITRE ATT&CK
- Use of threat modeling tools for structured analysis
Threat prioritization:
- Assess likelihood and impact of identified threats
- Consider cost and effort required for mitigation
- Focus on threats with highest risk-to-effort ratio
### Response and Mitigations (What are we going to do about it?)
Define responses for each identified threat using these strategies:
Response Options:
- Mitigate: Reduce likelihood that threat will materialize
- Eliminate: Remove feature or component causing the threat
- Transfer: Shift responsibility to another entity
- Accept: Acknowledge risk but take no action due to business constraints
Mitigation requirements:
- Develop actionable mitigation strategies that can be implemented
- Document mitigations as testable requirements
- Reference standards like OWASP ASVS and MITRE CWE for guidance
- Apply mitigations at category or individual threat level
- Ensure mitigations are built into the system, not theoretical
### Review and Validation (Did we do a good enough job?)
Validate threat model completeness and effectiveness through stakeholder review.
Review criteria:
- Does the model accurately reflect the actual system?
- Have all applicable threats been identified?
- Has a response strategy been defined for each threat?
- Do mitigation strategies reduce risk to acceptable levels?
- Is the threat model formally documented and accessible?
- Can mitigations be tested and measured for effectiveness?
Review participants:
- Development teams
- Security teams
- Architecture teams
- Product stakeholders
- Operations teams
### Integration with Development Process
Integrate threat modeling seamlessly into SDLC:
- Perform initial threat modeling during design phase
- Update threat models when system architecture changes
- Include threat modeling in feature development workflows
- Treat as standard development step, not optional add-on
- Maintain and refine models alongside system evolution
Development team considerations:
- Provide security training for developers
- Include security experts in threat modeling sessions
- Use tools that simplify and automate threat identification
- Promote security culture within development organization
- Establish cross-team collaboration and communication
Tools and techniques:
- OWASP Threat Dragon for collaborative threat modeling
- Microsoft Threat Modeling Tool for structured analysis
- OWASP pytm for threat-modeling-as-code approach
- draw.io with threat modeling libraries for diagramming
- STRIDE, PASTA, LINDDUN, OCTAVE, and VAST methodologies
### Implementation Guidelines
1. Start threat modeling early in design phase and integrate into SDLC
2. Create comprehensive Data Flow Diagrams showing trust boundaries and data flows
3. Apply STRIDE methodology systematically to identify threats
4. Prioritize threats based on likelihood, impact, and mitigation cost
5. Develop actionable, testable mitigation requirements
6. Involve security experts and cross-functional stakeholders in reviews
7. Document threat models and store artifacts accessibly
8. Update threat models when system architecture or features change
9. Use appropriate tools to support and streamline the process
10. Foster security awareness and collaboration across development teams
================================================
FILE: sources/owasp/codeguard-0-transaction-authorization.md
================================================
---
description: Transaction Authorization Security
languages:
- c
- go
- java
- javascript
- php
- python
- ruby
- typescript
alwaysApply: false
---
## Transaction Authorization Security
Secure implementation of transaction authorization to prevent bypassing of sensitive operations like wire transfers through robust user confirmation and server-side enforcement.
### Transaction Authorization Concept
Transaction authorization requires users to submit a second factor to verify authorization for sensitive operations. This applies beyond financial systems to any operation requiring explicit user consent (account unlocks, privilege changes, data modifications).
Authorization methods include:
- Time-based one-time password (OTP) tokens (OATH TOTP)
- OTP sent by SMS or phone
- Digital signatures from smart cards or smartphones
- Challenge-response tokens including unconnected card readers
- Transaction authorization cards with unique numbers
### Functional Requirements
#### User Identification and Acknowledgment (What You See Is What You Sign)
Transaction authorization must allow users to identify and acknowledge significant transaction data.
Key principles:
- User must verify all significant transaction data during authorization process
- Display critical information: target account, amount, transaction type
- Balance security requirements with user experience and technical constraints
- For external devices with limited displays, show minimum significant data (partial account number, amount)
- Ensure meaningful prompts to prevent social engineering and malware abuse
#### Authorization Token and Method Changes
- Changes to authorization tokens require authorization using current authorization credentials
- Changes to authorization methods require authorization using current authorization method
- Prevent malware from downgrading to least secure authorization method
- Inform users about potential dangers of different authorization methods
#### Authentication vs Authorization Separation
Distinguish authentication process from transaction authorization process to prevent credential reuse attacks.
Prevention strategies:
- Use different methods for authentication and transaction authorization
- Employ different actions in external security components
- Present clear messages about what users are signing
- Prevent malware from using authentication credentials for transaction authorization
#### Unique Authorization per Transaction
Each transaction requires unique authorization credentials to prevent replay attacks and credential reuse during sessions.
### Non-Functional Requirements
#### Server-Side Enforcement
All authorization checks must be performed and enforced server-side.
Implementation requirements:
- Never allow client-side influence on authorization results
- Prevent tampering with transaction data parameters
- Prevent adding/removing parameters that disable authorization checks
- Apply security programming best practices (default deny, no debug code in production)
- Encrypt data for confidentiality and integrity, verify server-side
#### Authorization Method Enforcement
Server-side must enforce chosen authorization method or application policies.
Security considerations:
- Prevent client-side manipulation of authorization method parameters
- Avoid building new authorization methods on old insecure codebases
- Ensure attackers cannot downgrade to older, less secure methods
#### Server-Side Transaction Verification
Generate and store all significant transaction data server-side.
Requirements:
- All transaction data must be verified by user and generated server-side
- Pass data to authorization component without client tampering possibility
- Prevent malware manipulation of transaction data display
#### Brute-Force Protection
Implement protections against authorization credential brute-force attacks.
Controls:
- Restart entire transaction authorization process after failed attempts
- Apply throttling and retry limits
- Use additional automation prevention techniques
#### Transaction State Control
Enforce sequential transaction state transitions.
Standard transaction flow:
1. User enters transaction data
2. User requests authorization from application
3. Application initializes authorization mechanism
4. User verifies/confirms transaction data
5. User responds with authorization credentials
6. Application validates authorization and executes transaction
Protection measures:
- Prevent out-of-order step execution
- Prevent step skipping
- Protect against transaction data overwriting before authorization
- Prevent skipping transaction authorization entirely
#### Transaction Data Protection
Protect transaction data against modification during authorization process.
Implementation strategies:
- Invalidate authorization data if transaction data is modified
- Reset authorization process on transaction data modifications
- Log, monitor, and investigate modification attempts
- Prevent Time of Check to Time of Use vulnerabilities
#### Data Confidentiality
Protect transaction data privacy during all client-server communications throughout the authorization process.
#### Transaction Execution Verification
Implement final control gate before transaction execution.
Verification requirements:
- Verify transaction was properly authorized by user
- Prevent Time of Check to Time of Use attacks
- Prevent authorization check bypass in transaction entry process
#### Time-Limited Authorization
Limit authorization credential validity to prevent delayed abuse by malware.
Controls:
- Restrict time window between challenge/OTP generation and authorization completion
- Balance security with normal user behavior
- Help prevent resource exhaustion attacks
#### Unique Authorization Credentials
Generate unique authorization credentials for every operation to prevent replay attacks.
Generation methods:
- Use timestamps in signed transaction data
- Include sequence numbers in challenges
- Use random values in authorization components
### Implementation Considerations
#### Risk-Based Authorization
Determine which transactions require authorization based on:
- Risk analysis of specific application
- Risk exposure assessment
- Other implemented safeguards
#### Cryptographic Protection
Implement cryptographic operations to ensure:
- Transaction integrity
- Data confidentiality
- Non-repudiation of transactions
#### Secure Key Management
Protect device signing keys during device pairing and signing protocol.
Security measures:
- Prevent malware injection/replacement of signing keys
- Use second factors for key protection (passwords, biometrics)
- Leverage secure elements (TEE, TPM, smart cards)
#### User Awareness
Train users on secure practices:
- Verify transaction data from trusted sources, not computer screens
- Understand risks of different authorization mechanisms
- Recognize social engineering attempts
#### Anti-Malware Integration
Deploy anti-malware solutions as additional protection layer while recognizing they cannot provide 100% effectiveness.
### Security Controls Summary
1. Implement What You See Is What You Sign principle for transaction data verification
2. Separate authentication from transaction authorization processes
3. Use unique, time-limited authorization credentials per transaction
4. Enforce all authorization logic server-side without client trust
5. Protect authorization token and method changes through re-authorization
6. Prevent authorization method downgrade attacks
7. Implement brute-force protection with transaction resets
8. Enforce sequential transaction state transitions
9. Protect transaction data against modification during authorization
10. Secure all client-server communications with encryption
11. Verify proper authorization before transaction execution
12. Use cryptographic signing and secure key storage for integrity
13. Monitor and log suspicious authorization activities
14. Provide user education on authorization security practices
================================================
FILE: sources/owasp/codeguard-0-transport-layer-security.md
================================================
---
description: Transport Layer Security
languages:
- c
- go
- java
- javascript
- php
- python
- ruby
- typescript
- yaml
alwaysApply: false
---
## Transport Layer Security
Secure implementation of TLS to protect client-server communications with confidentiality, integrity, and authentication through proper protocol, cipher, and certificate configuration.
### TLS Security Benefits
When correctly implemented, TLS provides:
- Confidentiality: Protection against attackers reading traffic contents
- Integrity: Protection against traffic modification and replay attacks
- Authentication: Client confirmation of legitimate server connection
### Protocol Security
#### Use Strong TLS Protocols Only
General purpose web applications should default to TLS 1.3 with TLS 1.2 support if necessary.
Protocol requirements:
- Enable TLS 1.3 by default
- Support TLS 1.2 only if legacy client compatibility required
- Disable TLS 1.0, TLS 1.1, SSL v2, and SSL v3 completely
- Enable TLS_FALLBACK_SCSV extension to prevent downgrade attacks when fallback necessary
- Note: PCI DSS forbids legacy protocols such as TLS 1.0
#### Configure Strong Cipher Suites
Use only strong ciphers that provide adequate security levels.
Cipher requirements:
- Prefer GCM ciphers where possible
- Always disable null ciphers, anonymous ciphers, and EXPORT ciphers
- Use Mozilla Foundation secure configuration generator for balanced security and compatibility
#### Set Appropriate Diffie-Hellman Groups
Configure secure Diffie-Hellman parameters for key exchange.
TLS 1.3 groups: ffdhe2048, ffdhe3072, ffdhe4096, ffdhe6144, ffdhe8192
Configuration examples:
```text
# OpenSSL configuration
openssl_conf = openssl_init
[openssl_init]
ssl_conf = ssl_module
[ssl_module]
system_default = tls_system_default
[tls_system_default]
Groups = x25519:prime256v1:x448:ffdhe2048:ffdhe3072
```
```text
# Apache configuration
SSLOpenSSLConfCmd Groups x25519:secp256r1:ffdhe3072
```
```text
# NGINX configuration
ssl_ecdh_curve x25519:secp256r1:ffdhe3072;
```
#### Disable TLS Compression
Disable TLS compression to protect against CRIME attacks that could recover sensitive information like session cookies.
#### Keep Cryptographic Libraries Updated
Maintain current versions of SSL/TLS libraries to protect against vulnerabilities like Heartbleed.
### Certificate Management
#### Use Strong Keys and Protection
Generate certificates with minimum 2048-bit key size and protect private keys from unauthorized access using filesystem permissions and access controls.
#### Use Strong Cryptographic Hashing
Certificates should use SHA-256 for hashing algorithm rather than deprecated MD5 and SHA-1 algorithms.
#### Use Correct Domain Names
Certificate domain names must match server's FQDN in both commonName (CN) and subjectAlternativeName (SAN) attributes.
#### Consider Wildcard Certificate Risks
Wildcard certificates violate principle of least privilege. Use only when genuine need exists and never for systems at different trust levels.
#### Use Appropriate Certificate Authority
Choose trusted CAs for Internet-facing applications. Consider LetsEncrypt for free domain validated certificates.
### Application Implementation
#### Use TLS for All Pages
Implement TLS for entire application with HTTP 301 redirects and HSTS header support.
#### Prevent Mixed Content
Load all JavaScript, CSS, and resources over HTTPS to prevent session cookie sniffing and malicious code injection.
#### Use Secure Cookie Flag
Mark all cookies with "Secure" attribute to restrict transmission to encrypted HTTPS connections only.
#### Prevent Sensitive Data Caching
Use cache prevention headers:
```text
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: 0
```
#### Implement HTTP Strict Transport Security
HSTS instructs browsers to always request site over HTTPS and prevents bypassing certificate warnings.
#### Consider Client Certificates and Mutual TLS
mTLS provides mutual authentication but involves significant administrative overhead. Recommended for high-value applications with technically sophisticated users.
#### Avoid Public Key Pinning in Browsers
HPKP deprecated and no longer supported by modern browsers. Consider pinning only in controlled environments.
### Testing and Validation
Test TLS configuration using tools like SSL Labs Server Test, testssl.sh, SSLyze, and other recommended online and offline testing tools.
### Implementation Guidelines
1. Default to TLS 1.3 with TLS 1.2 fallback only if necessary
2. Disable all legacy protocols (TLS 1.0/1.1, SSL v2/v3)
3. Configure strong cipher suites with GCM preference
4. Set appropriate Diffie-Hellman groups for key exchange
5. Disable TLS compression to prevent CRIME attacks
6. Use minimum 2048-bit certificate keys with SHA-256 hashing
7. Ensure correct domain names in certificate CN and SAN fields
8. Implement HTTPS for all pages with 301 redirects from HTTP
9. Prevent mixed content by loading all resources over HTTPS
10. Set Secure flag on all cookies
11. Prevent sensitive data caching with appropriate HTTP headers
12. Implement HSTS for browser enforcement
13. Consider mTLS for high-value applications
14. Avoid public key pinning in browsers
15. Regular testing of TLS configuration with recommended tools
================================================
FILE: sources/owasp/codeguard-0-unvalidated-redirects-and-forwards.md
================================================
---
description: Unvalidated Redirects and Forwards Prevention
languages:
- c
- java
- javascript
- php
- ruby
- rust
- typescript
alwaysApply: false
---
## Unvalidated Redirects and Forwards Prevention
Prevent open redirect and forward vulnerabilities by validating all user-controlled redirect destinations to stop phishing attacks and access control bypass.
### Security Risks
Unvalidated redirects and forwards occur when applications accept untrusted input for redirect destinations, enabling:
- Phishing attacks by redirecting users to malicious sites while maintaining trusted domain appearance
- Access control bypass by forwarding to privileged functions normally restricted
- User credential theft through convincing redirect to attacker-controlled sites
### Safe Redirect Examples
Secure redirects use hardcoded URLs that cannot be manipulated by attackers:
Java:
```java
response.sendRedirect("http://www.mysite.com");
```
PHP:
```php
```
ASP .NET:
```csharp
Response.Redirect("~/folder/Login.aspx")
```
Rails:
```ruby
redirect_to login_path
```
Rust actix web:
```rust
Ok(HttpResponse::Found()
.insert_header((header::LOCATION, "https://mysite.com/"))
.finish())
```
### Dangerous Redirect Examples
Vulnerable code accepts user input directly for redirect destinations:
Java:
```java
response.sendRedirect(request.getParameter("url"));
```
PHP:
```php
$redirect_url = $_GET['url'];
header("Location: " . $redirect_url);
```
C# .NET:
```csharp
string url = request.QueryString["url"];
Response.Redirect(url);
```
Rails:
```ruby
redirect_to params[:url]
```
Rust actix web:
```rust
Ok(HttpResponse::Found()
.insert_header((header::LOCATION, query_string.path.as_str()))
.finish())
```
ASP.NET MVC vulnerable example:
```csharp
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (MembershipService.ValidateUser(model.UserName, model.Password))
{
FormsService.SignIn(model.UserName, model.RememberMe);
if (!String.IsNullOrEmpty(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
```
Attack example:
```text
http://example.com/example.php?url=http://malicious.example.com
```
### Dangerous Forward Examples
Server-side forwards can bypass access controls when user input determines the forward destination:
Java servlet vulnerable forward:
```java
public class ForwardServlet extends HttpServlet
{
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String query = request.getQueryString();
if (query.contains("fwd"))
{
String fwd = request.getParameter("fwd");
try
{
request.getRequestDispatcher(fwd).forward(request, response);
}
catch (ServletException e)
{
e.printStackTrace();
}
}
}
}
```
Attack example:
```text
http://www.example.com/function.jsp?fwd=admin.jsp
```
### Prevention Strategies
#### Avoid User Input for Destinations
Simply avoid using redirects and forwards, or do not allow URLs as user input for destinations.
#### Use Server-Side Mapping
Have users provide short name, ID, or token mapped server-side to full target URL.
Benefits:
- Highest degree of protection against URL tampering
- Prevents direct URL manipulation
Considerations:
- Prevent enumeration vulnerabilities where users cycle through IDs
- Use sufficiently large or complex token spaces
#### Input Validation and Authorization
If user input cannot be avoided:
- Ensure supplied value is valid and appropriate for the application
- Verify user is authorized for the redirect/forward target
- Validate before performing redirect or forward
#### Allow-List Approach
Create and enforce list of trusted URLs or hosts:
- Use allow-list approach rather than deny-list
- Sanitize input against trusted URL list
- Consider regex patterns for flexible matching
#### External Redirect Warning
Force external redirects through interstitial warning page:
- Clearly display destination to users
- Require user confirmation before proceeding
- Helps users identify potential phishing attempts
#### Framework-Specific Considerations
PHP:
- Always follow header("Location: ...") with exit; to stop execution
- Prevents continued code execution after redirect
ASP.NET MVC:
- MVC 1 & 2 particularly vulnerable to open redirection attacks
- Use MVC 3 or later to avoid vulnerabilities
### Implementation Guidelines
1. Use hardcoded URLs for redirects whenever possible
2. Implement server-side mapping for user-controlled redirects
3. Validate all user input against allow-list of permitted destinations
4. Verify user authorization before performing redirects or forwards
5. Use interstitial warnings for external redirects
6. Follow framework-specific security practices
7. Prevent enumeration through complex token spaces
8. Keep frameworks updated with security patches
9. Never trust user input for determining redirect destinations
10. Test redirect functionality for bypass attempts
================================================
FILE: sources/owasp/codeguard-0-user-privacy-protection.md
================================================
---
description: User Privacy Protection Rule
languages:
- c
- go
- java
- javascript
- kotlin
- python
- ruby
- swift
- typescript
alwaysApply: false
---
- Implement strong cryptography, enforce HTTPS with HSTS, enable certificate pinning,
and provide user privacy features to protect data and anonymity.
- Use strong, up-to-date cryptographic algorithms for data in transit and at rest; securely hash passwords with established libraries.
- Enforce HTTPS exclusively and implement HTTP Strict Transport Security (HSTS).
- Implement certificate pinning to prevent man-in-the-middle attacks even if CAs are compromised.
- Minimize IP address leakage by blocking third-party external content loading where feasible.
- Maintain transparency by informing users about privacy limitations and data handling policies.
- Implement privacy-focused audit trails and access logging.
- Return "Invalid username or password" to prevent account enumeration
- Use Argon2 or bcrypt with unique salts per user
- Store sessions server-side with cryptographically random IDs
================================================
FILE: sources/owasp/codeguard-0-virtual-patching.md
================================================
---
description: Virtual Patching Security
languages:
- c
- go
- java
- javascript
- php
- python
- ruby
- typescript
- xml
alwaysApply: false
---
## Virtual Patching Security
Implement temporary security controls to protect against known vulnerabilities while developing permanent code fixes through security policy enforcement layers.
### Virtual Patching Definition
A security policy enforcement layer which prevents and reports exploitation attempts of known vulnerabilities. Virtual patches analyze transactions and intercept attacks in transit so malicious traffic never reaches the web application, providing protection while actual source code remains unmodified.
### When Virtual Patching is Needed
Virtual patching addresses real-world scenarios where immediate code fixes are not feasible:
- Lack of resources: Developers allocated to other projects
- Third-party software: Code cannot be modified by users
- Outsourced development: Changes require new project authorization
Important: Code level fixes and virtual patching are NOT mutually exclusive. They are executed by different teams (developers vs. security operations) and can run in tandem.
### Virtual Patching Goals
- Minimize Time-to-Fix: Implement mitigation as soon as possible while code fixes are developed
- Attack Surface Reduction: Focus on minimizing attack vectors, even partial reduction (50% in 10 minutes vs 100% in 48 hours)
### Virtual Patching Tools
Available tools for implementing virtual patches:
- Intermediary devices such as WAF or IPS appliances
- Web server plugins such as ModSecurity
- Application layer filters such as ESAPI WAF
### Virtual Patching Methodology
Follow structured workflow for consistent, repeatable virtual patching:
1. Preparation
2. Identification
3. Analysis
4. Virtual Patch Creation
5. Implementation/Testing
6. Recovery/Follow-Up
### Preparation Phase
Critical preparation items before incidents occur:
- Public/Vendor Vulnerability Monitoring: Subscribe to vendor alert mailing lists for commercial software
- Virtual Patching Pre-Authorization: Expedite governance processes since virtual patches don't modify source code
- Deploy Virtual Patching Tools in Advance: Install ModSecurity WAF or similar tools ready for activation
- Increase HTTP Audit Logging: Capture request URI, full headers, request/response bodies for incident analysis
### Analysis Phase
Recommended analysis steps:
1. Determine virtual patching applicability for vulnerability type
2. Utilize bug tracking system for vulnerability information management
3. Verify vulnerability identifier (CVE name/number)
4. Designate impact level for proper prioritization
5. Specify affected software versions
6. List configuration requirements to trigger vulnerability
7. Collect Proof of Concept (PoC) exploit code for analysis and testing
### Virtual Patch Creation Principles
Two main requirements for accurate virtual patches:
- No false positives: Never block legitimate traffic
- No false negatives: Never miss attacks, even with evasion attempts
### Positive Security (Allow List) Virtual Patches (Recommended)
Positive security model provides comprehensive input validation by specifying valid input characteristics and denying anything non-conformant.
Example ModSecurity virtual patch for SQL injection protection:
```text
##
## Verify we only receive 1 parameter called "reqID"
##
SecRule REQUEST_URI "@contains /wp-content/plugins/levelfourstorefront/scripts/administration/exportsubscribers.php" "chain,id:1,phase:2,t:none,t:Utf8toUnicode,t:urlDecodeUni,t:normalizePathWin,t:lowercase,block,msg:'Input Validation Error for \'reqID\' parameter - Duplicate Parameters Names Seen.',logdata:'%{matched_var}'"
SecRule &ARGS:/reqID/ "!@eq 1"
##
## Verify reqID's payload only contains integers
##
SecRule REQUEST_URI "@contains /wp-content/plugins/levelfourstorefront/scripts/administration/exportsubscribers.php" "chain,id:2,phase:2,t:none,t:Utf8toUnicode,t:urlDecodeUni,t:normalizePathWin,t:lowercase,block,msg:'Input Validation Error for \'reqID\' parameter.',logdata:'%{args.reqid}'"
SecRule ARGS:/reqID/ "!@rx ^[0-9]+$"
```
### Negative Security (Block List) Virtual Patches
Negative security model detects specific known attacks rather than allowing only valid traffic.
Example PoC attack payload:
```text
http://localhost/wordpress/wp-content/plugins/levelfourstorefront/scripts/administration/exportsubscribers.php?reqID=1' or 1='1
```
Example ModSecurity block list virtual patch:
```text
SecRule REQUEST_URI "@contains /wp-content/plugins/levelfourstorefront/scripts/administration/exportsubscribers.php" "chain,id:1,phase:2,t:none,t:Utf8toUnicode,t:urlDecodeUni,t:normalizePathWin,t:lowercase,block,msg:'Input Validation Error for \'reqID\' parameter.',logdata:'%{args.reqid}'"
SecRule ARGS:/reqID/ "@pm '"
```
### Security Model Comparison
Positive vs Negative Security considerations:
- Negative security: Faster implementation but more evasion possibilities
- Positive security: Better protection but manual process, less scalable for large/dynamic sites
- Positive security recommended for specific vulnerability locations identified by alerts
### Avoid Exploit-Specific Patches
Resist creating patches that only block exact exploit payloads. Example poor approach for XSS:
```html
```
Blocking only this exact payload provides minimal long-term protection value.
### Automated Virtual Patch Creation
Tools for automated patch creation from vulnerability reports:
- OWASP ModSecurity Core Rule Set (CRS) Scripts: Auto-convert XML output from tools like ZAP
- ThreadFix Virtual Patching: Convert vulnerability XML data into ModSecurity patches
- Direct WAF Importing: Commercial WAF products import DAST tool XML reports
### Implementation and Testing
Testing tools for virtual patch validation:
- Web browsers
- Command-line clients (Curl, Wget)
- Local proxy servers (ZAP)
- ModSecurity AuditViewer for log manipulation and re-injection
Testing steps:
- Implement patches initially in "Log Only" mode to prevent false positives
- Request retest from vulnerability identification team
- Return to analysis phase if evasions occur during retesting
### Recovery and Follow-Up
Post-implementation activities:
- Update ticket system with virtual patch details and rule IDs
- Conduct periodic re-assessments to determine when virtual patches can be removed
- Run virtual patch alert reports to demonstrate protection value
- Track time-to-fix metrics for different vulnerability types
### Developer Integration Guidelines
1. Prioritize permanent code fixes over virtual patches
2. Collaborate with security teams on virtual patch requirements and testing
3. Understand virtual patch limitations and temporary nature
4. Provide input on normal application behavior for positive security rules
5. Review virtual patch logs for attack patterns that inform secure coding practices
6. Plan code fixes to address root causes protected by virtual patches
7. Participate in virtual patch removal process once code fixes are deployed
8. Document application-specific requirements for virtual patch creation
================================================
FILE: sources/owasp/codeguard-0-vulnerable-dependency-management.md
================================================
---
description: Vulnerable Dependency Management
languages:
- c
- go
- javascript
- r
- xml
alwaysApply: false
---
## Vulnerable Dependency Management
Detect and mitigate security vulnerabilities in third-party dependencies through automated scanning, proper testing, and systematic remediation approaches.
### Automated Detection
Integrate vulnerability scanning from project inception using tools that cover multiple vulnerability sources:
- CVE databases (NIST National Vulnerability Database)
- Full disclosure sources (mailing lists, Exploit-DB)
- Provider-specific vulnerability feeds
Recommended tools:
- OWASP Dependency Check (Java, .NET, experimental support for Python, Ruby, PHP, Node.js, C/C++)
- NPM Audit (Node.js, JavaScript)
- OWASP Dependency Track (organization-wide management)
### Remediation Cases
Case 1 - Patched version available:
1. Update dependency version in testing environment
2. Run automated tests to verify functionality
3. If tests pass: deploy to production
4. If tests fail: update application code for API changes or report incompatibility to provider
Case 2 - Patch delayed, provider provides workaround:
1. Apply provider workaround if available
2. If provider lists impacted functions, add protective wrappers
3. Validate workaround in testing environment
Example protective wrapper for RCE vulnerability:
```java
public void callFunctionWithRCEIssue(String externalInput){
//Apply input validation on the external input using regex
if(Pattern.matches("[a-zA-Z0-9]{1,50}", externalInput)){
//Call the flawed function using safe input
functionWithRCEIssue(externalInput);
}else{
//Log the detection of exploitation
SecurityLogger.warn("Exploitation of the RCE issue XXXXX detected !");
//Raise an exception leading to a generic error send to the client...
}
}
```
Case 3 - No patch available:
1. Analyze CVE description to understand vulnerability type (SQL injection, XSS, XXE, etc.)
2. Identify all application code calling the vulnerable dependency
3. Implement compensating controls based on vulnerability type
4. Create unit tests to verify protection effectiveness
5. For open source dependencies: consider creating and contributing patches
Case 4 - Previously unknown vulnerability discovered:
1. Notify provider with vulnerability details
2. If provider cooperates: follow Case 2 approach
3. If provider unresponsive: follow Case 3 approach
### Dependencies Analysis
Transitive dependencies: Act on direct dependencies when possible, as modifying transitive dependencies requires understanding complex dependency chains and can impact application stability.
Use dependency management tools to identify:
- Direct vs transitive dependency relationships
- All code paths using vulnerable components
- Impact scope of potential vulnerabilities
### Testing and Validation
Maintain comprehensive automated tests covering:
- Features using impacted dependencies
- Security controls added as mitigations
- Regression detection during updates
Run tests before and after dependency updates to ensure:
- Application functionality remains intact
- Security mitigations are effective
- No new vulnerabilities are introduced
### Risk Management
Document all vulnerability decisions including:
- Technical analysis and CVSS scoring
- Chosen mitigation approach and rationale
- Testing results and validation steps
- Risk acceptance decisions with business justification
Escalate risk acceptance decisions to Chief Risk Officer after thorough technical analysis.
### Continuous Monitoring
Implement continuous dependency scanning in CI/CD pipelines:
- Scan on every build
- Fail builds for high-severity vulnerabilities
- Generate reports for security team review
- Track remediation progress and compliance
Choose tools supporting false-positive flagging and multiple reliable input sources to handle different vulnerability disclosure methods.
### Prevention Guidelines
- Start dependency scanning from project inception
- Prefer fixing vulnerabilities at source (application or dependency) over external controls
- Keep dependencies updated regularly
- Monitor dependencies for maintenance status and community activity
- Consider dependency complexity and transitive dependency count when selecting libraries
================================================
FILE: sources/owasp/codeguard-0-web-service-security.md
================================================
---
description: Web Service Security
languages:
- c
- go
- java
- javascript
- php
- python
- ruby
- typescript
- xml
alwaysApply: false
---
## Web Service Security
Secure web services through transport protection, authentication, input validation, and XML attack prevention.
### Transport Security
All web service communications with sensitive features or data must use well-configured TLS. TLS provides confidentiality, integrity protection, replay defenses, and server authentication.
Server certificate validation requirements:
- Issued by trusted provider
- Not expired or revoked
- Matches service domain name
- Proven private key ownership
### Authentication
- Avoid Basic Authentication; use Client Certificate Authentication with Mutual-TLS when appropriate
- Enforce consistent encoding styles between client and server
### Message Protection
For XML data requiring integrity beyond TLS:
- Use XML digital signatures with sender's private key
- Encrypt sensitive data with strong ciphers for both transport and at-rest protection when required
### Authorization
- Authorize clients for every web service method and request
- Check privileges for requested resources on every request
- Separate administrative functions from regular service endpoints
- Add challenge-response mechanisms for sensitive operations (password changes, contact details, payment instructions)
### Input Validation
Schema validation:
- Validate SOAP payloads against XML schema definition (XSD)
- Define maximum length and character sets for all parameters
- Use strong allow-list patterns for fixed format parameters (zip codes, phone numbers)
Content validation for XML input:
- Validate against malformed XML entities
- Validate against XML Bomb attacks
- Use strong allowlists for input validation
- Validate against external entity attacks
### XML Attack Protection
Configure XML parsers to protect against:
- Recursive payloads
- Oversized payloads
- XML entity expansion
- Overlong element names (SOAP Actions)
Build test cases to verify parser resistance to these attacks.
### Output Protection
Apply proper output encoding to prevent XSS when web service data is consumed by web clients.
### Resource Protection
- Limit SOAP message sizes to prevent DoS attacks
- Limit CPU cycles, memory usage, and simultaneous connections
- Optimize configuration for maximum message throughput
- Implement virus scanning for SOAP attachments before storage
### Compliance
Ensure compliance with Web Services-Interoperability (WS-I) Basic Profile for security baseline.
================================================
FILE: sources/owasp/codeguard-0-xml-external-entity-prevention.md
================================================
---
description: XML External Entity Prevention
languages:
- c
- java
- matlab
- php
- python
- swift
- xml
alwaysApply: false
---
## XML External Entity Prevention
Prevent XXE attacks by disabling DTDs and external entities in XML parsers. Safest approach: disable DTDs completely.
### General Principle
```java
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
```
Disabling DTDs protects against XXE and Billion Laughs attacks. If DTDs cannot be disabled, disable external entities using parser-specific methods.
### Java
Java parsers have XXE enabled by default.
DocumentBuilderFactory/SAXParserFactory/DOM4J:
```java
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
String FEATURE = null;
try {
// PRIMARY defense - disallow DTDs completely
FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
dbf.setFeature(FEATURE, true);
dbf.setXIncludeAware(false);
} catch (ParserConfigurationException e) {
logger.info("ParserConfigurationException was thrown. The feature '" + FEATURE
+ "' is not supported by your XML processor.");
}
```
If DTDs cannot be completely disabled:
```java
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
String[] featuresToDisable = {
"http://xml.org/sax/features/external-general-entities",
"http://xml.org/sax/features/external-parameter-entities",
"http://apache.org/xml/features/nonvalidating/load-external-dtd"
};
for (String feature : featuresToDisable) {
try {
dbf.setFeature(feature, false);
} catch (ParserConfigurationException e) {
logger.info("ParserConfigurationException was thrown. The feature '" + feature
+ "' is probably not supported by your XML processor.");
}
}
dbf.setXIncludeAware(false);
dbf.setExpandEntityReferences(false);
dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
```
XMLInputFactory (StAX):
```java
xmlInputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
// Or if DTDs needed:
xmlInputFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
xmlInputFactory.setProperty("javax.xml.stream.isSupportingExternalEntities", false);
```
TransformerFactory:
```java
TransformerFactory tf = TransformerFactory.newInstance();
tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
```
XMLReader:
```java
XMLReader reader = XMLReaderFactory.createXMLReader();
reader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
reader.setFeature("http://xml.org/sax/features/external-general-entities", false);
reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
```
SAXBuilder:
```java
SAXBuilder builder = new SAXBuilder();
builder.setFeature("http://apache.org/xml/features/disallow-doctype-decl",true);
Document doc = builder.build(new File(fileName));
```
No-op EntityResolver:
```java
public final class NoOpEntityResolver implements EntityResolver {
public InputSource resolveEntity(String publicId, String systemId) {
return new InputSource(new StringReader(""));
}
}
xmlReader.setEntityResolver(new NoOpEntityResolver());
documentBuilder.setEntityResolver(new NoOpEntityResolver());
```
Never use java.beans.XMLDecoder on untrusted content - it can execute arbitrary code.
### .NET
XmlReader (.NET 4.5.2+ safe by default):
```csharp
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Prohibit;
settings.XmlResolver = null;
XmlReader reader = XmlReader.Create(stream, settings);
```
XmlTextReader (prior to .NET 4.0):
```csharp
XmlTextReader reader = new XmlTextReader(stream);
reader.ProhibitDtd = true;
```
XmlTextReader (.NET 4.0 - 4.5.2):
```csharp
XmlTextReader reader = new XmlTextReader(stream);
reader.DtdProcessing = DtdProcessing.Prohibit;
```
XmlDocument (prior to 4.5.2):
```csharp
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.XmlResolver = null;
xmlDoc.LoadXml(xml);
```
XPathNavigator (prior to 4.5.2):
```csharp
XmlReader reader = XmlReader.Create("example.xml");
XPathDocument doc = new XPathDocument(reader);
XPathNavigator nav = doc.CreateNavigator();
string xml = nav.InnerXml.ToString();
```
### C/C++
libxml2: Avoid XML_PARSE_NOENT and XML_PARSE_DTDLOAD options.
libxerces-c:
```cpp
XercesDOMParser *parser = new XercesDOMParser;
parser->setCreateEntityReferenceNodes(true);
parser->setDisableDefaultEntityResolution(true);
SAXParser* parser = new SAXParser;
parser->setDisableDefaultEntityResolution(true);
SAX2XMLReader* reader = XMLReaderFactory::createXMLReader();
parser->setFeature(XMLUni::fgXercesDisableDefaultEntityResolution, true);
```
### PHP
PHP 8.0+ prevents XXE by default. Earlier versions:
```php
libxml_set_external_entity_loader(null);
```
### Python
```python
from defusedxml import ElementTree as ET
tree = ET.parse('filename.xml')
# Or with lxml:
from lxml import etree
parser = etree.XMLParser(resolve_entities=False, no_network=True)
tree = etree.parse('filename.xml', parser)
```
### iOS/macOS
```swift
let options: NSXMLNodeOptions = .documentTidyXML
let xmlDoc = try NSXMLDocument(data: data, options: options.union(.nodeLoadExternalEntitiesNever))
```
### ColdFusion
Adobe ColdFusion:
```
a = XmlParse("xml.xml", false, parseroptions);
```
Lucee (Application.cfc):
```
this.xmlFeatures = {
externalGeneralEntities: false,
secure: true,
disallowDoctypeDecl: true
};
```
### Additional Measures
- Update XML libraries regularly
- Validate XML input before parsing
- Use static analysis tools for XXE detection
- Test with XXE payloads in safe environments
### When DTDs Required
If DTDs absolutely necessary:
- Use custom EntityResolver with restricted entities
- Implement strict entity allowlisting
- Preprocess XML to remove dangerous DOCTYPE declarations
================================================
FILE: sources/owasp/codeguard-0-xml-security.md
================================================
---
description: XML Security Rule
languages:
- xml
alwaysApply: false
---
Enforce robust XML security practices to prevent XXE, SSRF, DoS, schema poisoning, and data integrity issues in XML parsing and validation.
- Always reject unexpected elements, attributes, or data outside the schema definitions.
- Perform business logic validation on XML data after schema validation (e.g., numeric ranges on payment amounts).
- Keep XML processing libraries up to date and use secure configurations by default.
Use a standards-compliant XML parser configured to disable DTD processing and external entity resolution to prevent XXE and entity expansion attacks.
- Ensure your XML parser rejects malformed XML documents and halts processing on fatal errors.
- Configure parser features such as `disallow-doctype-decl`, `external-general-entities`, and `external-parameter-entities` set to false or disabled.
Validate all XML documents strictly against local, trusted XML Schemas (XSDs) with narrow data type restrictions and clearly defined element occurrence limits.
- Avoid or limit the use of DTDs; prefer comprehensive XSD validation.
- Use schemas with explicit types, length limits, regex patterns, enumerations, and xs:assertion where appropriate.
- Set maxOccurs explicitly to control element multiplicity.
- Store schemas locally with strict filesystem permissions and never load schemas over unencrypted HTTP.
Prevent resource exhaustion by rejecting XML documents with excessive depth, nested unclosed tags, or large size to avoid DoS.
- Enforce limits on XML element nesting depth and document size.
- Test parser CPU usage differences between valid and malformed XML inputs.
- Reject or timeout processing on unexpectedly complex documents.
Block or sandbox XML processing from making remote network calls to mitigate SSRF and information disclosure risks.
- Disable external entity resolution or restrict it to local, whitelisted resources only.
- Validate and sanitize all external URI references in XML entities.
- Monitor for unexpected DNS lookups or network activity during XML parsing.
Log and monitor XML parsing errors and rejections to detect injection attempts, malformed XML attacks, or schema poisoning.
- Capture detailed error information without exposing sensitive data.
- Alert on repeated or suspicious XML parse failures.
- Audit local schema files regularly for unauthorized changes.
================================================
FILE: sources/owasp/codeguard-0-xs-leaks.md
================================================
---
description: Preventing Cross-Site Leaks (XS-Leaks)
languages:
- c
- javascript
- typescript
alwaysApply: false
---
Protecting your applications from Cross-Site Leaks is crucial for safeguarding user privacy. XS-Leaks are a class of vulnerabilities that exploit subtle browser behaviors to extract sensitive user information across origins.
XS-Leaks occur when an attacker's website can infer information about a user's state on another website through side-channels like:
- Error messages
- Frame counting
- Resource timing
- Cache probing
- Response size detection
These attacks can reveal sensitive information such as whether a user is logged in, specific account details, or even extract data from cross-origin resources.
Properly configured cookies are your first line of defense against XS-Leaks. For example:
```javascript
// Setting cookies in JavaScript with secure attributes
document.cookie = "sessionId=abc123; SameSite=Strict; Secure; HttpOnly; Path=/";
```
For server-side cookie setting (example in Express.js):
```javascript
app.use(session({
secret: 'your-secret-key',
cookie: {
sameSite: 'strict', // Options: strict, lax, none
secure: true, // Requires HTTPS
httpOnly: true // Prevents JavaScript access
}
}));
```
In your HTTP response headers:
```http
Set-Cookie: sessionId=abc123; SameSite=Strict; Secure; HttpOnly; Path=/
```
* Always specify a `SameSite` attribute:
* Use `SameSite=Strict` for cookies related to sensitive actions
* Use `SameSite=Lax` for cookies needed on normal navigation to your site
* Use `SameSite=None; Secure` only when third-party usage is absolutely required
* Never rely on browser defaults as they may vary across browsers and versions
### Framing Protection
Prevent your site from being framed by potentially malicious sites:
```javascript
// In your Express.js application
app.use((req, res, next) => {
// CSP frame-ancestors directive (modern approach)
res.setHeader(
'Content-Security-Policy',
"frame-ancestors 'self' https://trusted-parent.com"
);
// X-Frame-Options (legacy fallback)
res.setHeader('X-Frame-Options', 'SAMEORIGIN');
next();
});
```
Use Fetch Metadata headers to detect and block suspicious cross-origin requests:
```javascript
// Express.js middleware for protecting sensitive endpoints
function secureEndpoint(req, res, next) {
// Get Fetch Metadata headers
const fetchSite = req.get('Sec-Fetch-Site') || 'unknown';
const fetchMode = req.get('Sec-Fetch-Mode') || 'unknown';
const fetchDest = req.get('Sec-Fetch-Dest') || 'unknown';
// Block cross-site requests to sensitive endpoints
if (fetchSite === 'cross-site' && req.path.startsWith('/api/sensitive')) {
return res.status(403).send('Cross-site requests not allowed');
}
// Block embedding in iframes from untrusted sites
if (fetchDest === 'iframe' && fetchSite === 'cross-site') {
return res.status(403).send('Embedding not allowed');
}
next();
}
app.use(secureEndpoint);
```
### Secure Cross-Origin Communication
When using `postMessage` for cross-origin communication:
```javascript
// UNSAFE - Never do this
window.postMessage(sensitiveData, '*');
// SAFE - Always specify the exact target origin
window.postMessage(sensitiveData, 'https://trusted-receiver.com');
// When receiving messages, always verify the origin
window.addEventListener('message', (event) => {
// Always verify message origin
if (event.origin !== 'https://trusted-sender.com') {
console.error('Received message from untrusted origin:', event.origin);
return;
}
// Process the message
processMessage(event.data);
});
```
### Isolating Browsing Contexts
Use Cross-Origin-Opener-Policy (COOP) to isolate your site from potential attackers:
```http
Cross-Origin-Opener-Policy: same-origin
```
In Express.js:
```javascript
app.use((req, res, next) => {
res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
next();
});
```
For maximum isolation, combine with Cross-Origin-Embedder-Policy (COEP):
```javascript
app.use((req, res, next) => {
res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp');
next();
});
```
### Preventing Cache-Based Leaks
Protect sensitive resources from cache probing attacks:
```javascript
// Express.js middleware for sensitive endpoints
app.get('/api/sensitive-data', (req, res) => {
// Add user-specific token to prevent cache probing
const userToken = req.user.securityToken;
// Disable caching for sensitive resources
res.setHeader('Cache-Control', 'no-store');
res.setHeader('Pragma', 'no-cache');
// Add user token to response to ensure uniqueness
const data = { userToken, sensitiveData: 'secret information' };
res.json(data);
});
```
For static resources that might reveal user state:
```javascript
// Add user-specific tokens to URLs of sensitive resources
function getUserSpecificUrl(baseUrl) {
const userToken = generateUserToken();
return `${baseUrl}?token=${userToken}`;
}
const profileImageUrl = getUserSpecificUrl('/images/profile.jpg');
```
### Comprehensive Defense Strategy
Implement these headers for a robust defense against XS-Leaks:
```javascript
app.use((req, res, next) => {
// Framing protection
res.setHeader('Content-Security-Policy', "frame-ancestors 'self'");
res.setHeader('X-Frame-Options', 'SAMEORIGIN');
// Resource isolation
res.setHeader('Cross-Origin-Resource-Policy', 'same-origin');
res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
// Cache control for dynamic content
if (req.path.startsWith('/api/')) {
res.setHeader('Cache-Control', 'no-store');
}
next();
});
```
================================================
FILE: sources/owasp/codeguard-0-xss-filter-evasion.md
================================================
---
description: XSS Filter Evasion Prevention - Advanced techniques attackers use to
bypass input filtering and blacklists
languages:
- c
- javascript
- typescript
alwaysApply: false
---
Relying solely on input filtering or blacklists is insufficient because attackers use numerous techniques to bypass these defenses:
- Mixed encoding schemes: Combining HTML, URL, and Unicode encodings
- Whitespace manipulation: Using tabs, newlines, and other whitespace characters to confuse parsers
- Malformed tags: Creating deliberately broken HTML that browsers will "fix" during rendering
- Obfuscation: Using JavaScript encoding functions like `String.fromCharCode()` to hide malicious code
### Context-Aware Output Encoding
The most effective defense is to apply the appropriate encoding based on where the data will be used:
#### HTML Context (Content between tags)
```javascript
// VULNERABLE
const userName = request.getParameter("user");
document.getElementById("welcome").innerHTML = "Hello, " + userName;
// SECURE
import { encodeForHTML } from 'your-encoding-library';
const userName = request.getParameter("user");
document.getElementById("welcome").innerHTML = "Hello, " + encodeForHTML(userName);
```
#### HTML Attribute Context
```javascript
// VULNERABLE
const userColor = request.getParameter("color");
document.getElementById("profile").innerHTML =
`Profile
`;
// SECURE
import { encodeForHTMLAttribute } from 'your-encoding-library';
const userColor = request.getParameter("color");
document.getElementById("profile").innerHTML =
`Profile
`;
```
#### JavaScript Context
```javascript
// VULNERABLE
const userInput = request.getParameter("input");
const script = document.createElement("script");
script.textContent = `const userValue = "${userInput}";`;
// SECURE
import { encodeForJavaScript } from 'your-encoding-library';
const userInput = request.getParameter("input");
const script = document.createElement("script");
script.textContent = `const userValue = "${encodeForJavaScript(userInput)}";`;
```
#### URL Context
```javascript
// VULNERABLE
const redirectUrl = request.getParameter("url");
location.href = redirectUrl;
// SECURE
import { encodeForURL } from 'your-encoding-library';
const redirectUrl = request.getParameter("url");
// Validate URL pattern first
if (isValidRedirectURL(redirectUrl)) {
location.href = encodeForURL(redirectUrl);
}
```
#### CSS Context
```javascript
// VULNERABLE
const userTheme = request.getParameter("theme");
document.getElementById("custom").style = userTheme;
// SECURE
import { encodeForCSS } from 'your-encoding-library';
const userTheme = request.getParameter("theme");
document.getElementById("custom").style = encodeForCSS(userTheme);
```
### Using Established Sanitization Libraries
Avoid creating your own sanitization logic. Use well-maintained libraries instead:
#### JavaScript/DOM
```javascript
// Using DOMPurify
import DOMPurify from 'dompurify';
function displayUserContent(content) {
// Configure DOMPurify to only allow specific tags and attributes
const config = {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a', 'p', 'ul', 'ol', 'li'],
ALLOWED_ATTR: ['href', 'target']
};
const sanitized = DOMPurify.sanitize(content, config);
document.getElementById('user-content').innerHTML = sanitized;
}
```
#### Java
```java
// Using OWASP Java Encoder
import org.owasp.encoder.Encode;
@Controller
public class UserController {
@GetMapping("/profile")
public String showProfile(Model model, @RequestParam String username) {
model.addAttribute("encodedUsername", Encode.forHtml(username));
return "profile";
}
}
// In your template (e.g., Thymeleaf)
// Username
```
#### PHP
```php
// Using HTMLPurifier
require_once 'HTMLPurifier.auto.php';
$config = HTMLPurifier_Config::createDefault();
$purifier = new HTMLPurifier($config);
$userBio = $_POST['bio'];
$cleanBio = $purifier->purify($userBio);
echo '' . $cleanBio . '
';
```
### Avoiding Dangerous Patterns
Certain coding patterns are particularly vulnerable to XSS attacks:
#### Avoid Unsafe JavaScript APIs
```javascript
// DANGEROUS - Never do this with user input
eval(userInput);
document.write(userInput);
new Function(userInput);
setTimeout(userInput, 100);
setInterval(userInput, 100);
element.innerHTML = userInput;
// SAFER ALTERNATIVES
// Instead of eval, parse JSON safely
const data = JSON.parse(userInput);
// Instead of innerHTML, use textContent
element.textContent = userInput;
// Or create elements properly
const div = document.createElement('div');
div.textContent = userInput;
parentElement.appendChild(div);
```
#### Avoid Inline Scripts and Event Handlers
```html
```
### Defense in Depth Strategy
Implement multiple layers of protection:
#### Content Security Policy (CSP)
```http
# Strong CSP header that blocks inline scripts and restricts sources
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; style-src 'self'; img-src 'self' data:;
```
```javascript
// Setting CSP in Express.js
const helmet = require('helmet');
app.use(helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", 'trusted-cdn.com'],
objectSrc: ["'none'"],
styleSrc: ["'self'"],
imgSrc: ["'self'", 'data:']
}
}));
```
#### Secure Cookie Configuration
```http
Set-Cookie: sessionId=abc123; HttpOnly; Secure; SameSite=Strict
```
#### Input Validation
```javascript
// Validate input format before processing
function validateUsername(username) {
// Only allow alphanumeric characters and limited symbols
const usernameRegex = /^[a-zA-Z0-9_.-]{3,30}$/;
if (!usernameRegex.test(username)) {
throw new Error('Invalid username format');
}
return username;
}
```
================================================
FILE: sources/owasp/codeguard-0-zero-trust-architecture.md
================================================
---
description: Zero Trust Architecture Implementation - Security principles for designing
systems with no implicit trust
languages:
- c
- go
- java
- javascript
- kotlin
- php
- python
- ruby
- scala
- shell
- swift
- typescript
- yaml
alwaysApply: false
---
## Implementing Zero Trust Architecture
Implementing Zero Trust Architecture (ZTA) principles in your applications is essential for modern security.
Zero Trust is built on the principle of "never trust, always verify" and assumes that threats exist both outside and inside the network. Key concepts include:
- No implicit trust based on network location or asset ownership
- Continuous verification of identity and device health
- Least privilege access to resources and data
- Microsegmentation of networks and applications
- Continuous monitoring and analytics for threat detection
### Authentication & Authorization
- Implement Strong Authentication using FIDO2/WebAuthn
- Implement Context-Aware Authorization
Implement authorization that considers multiple factors:
```java
// Java example of context-aware authorization
public class ZeroTrustAuthorizationService {
public boolean authorizeAccess(User user, Resource resource, AccessContext context) {
// 1. Verify user identity
if (!identityService.verifyIdentity(user)) {
logFailedAttempt("Identity verification failed", user, resource, context);
return false;
}
// 2. Check device health and compliance
if (!deviceService.isCompliant(context.getDeviceId())) {
logFailedAttempt("Device not compliant", user, resource, context);
return false;
}
// 3. Evaluate risk score based on multiple factors
int riskScore = riskEngine.calculateScore(user, resource, context);
if (riskScore > ACCEPTABLE_THRESHOLD) {
logFailedAttempt("Risk score too high", user, resource, context);
return false;
}
// 4. Check if user has required permissions
if (!permissionService.hasPermission(user, resource, context.getRequestedAction())) {
logFailedAttempt("Insufficient permissions", user, resource, context);
return false;
}
// 5. Log successful access
auditLogger.logAccess(user, resource, context);
return true;
}
}
```
- Implement Short-Lived Access Tokens
Implement token-based authentication with short lifetimes:
```python
# Python example using JWT with short expiration
import jwt
from datetime import datetime, timedelta
def generate_access_token(user_id, device_id, permissions):
# Set token to expire in 15 minutes
expiration = datetime.utcnow() + timedelta(minutes=15)
payload = {
'sub': user_id,
'device_id': device_id,
'permissions': permissions,
'exp': expiration,
'iat': datetime.utcnow(),
'jti': str(uuid.uuid4()) # Unique token ID
}
# Sign with appropriate algorithm and key
token = jwt.encode(payload, SECRET_KEY, algorithm='ES256')
# Store token metadata for potential revocation
store_token_metadata(user_id, payload['jti'], device_id, expiration)
return token
```
### Secure Communication
- Implement TLS 1.3 for all communications
- Implement API security measures:
```typescript
// TypeScript example of API security middleware
import express from 'express';
import rateLimit from 'express-rate-limit';
import helmet from 'helmet';
const app = express();
// Set security headers
app.use(helmet());
// Rate limiting
const apiLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per windowMs
standardHeaders: true,
legacyHeaders: false,
});
app.use('/api/', apiLimiter);
// API authentication middleware
app.use('/api/', (req, res, next) => {
const token = req.headers.authorization?.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'Authentication required' });
}
try {
// Verify token and extract user info
const user = verifyAndDecodeToken(token);
// Check if token has been revoked
if (isTokenRevoked(token)) {
return res.status(401).json({ error: 'Token revoked' });
}
// Add user info to request for downstream handlers
req.user = user;
next();
} catch (error) {
return res.status(401).json({ error: 'Invalid token' });
}
});
// Payload validation middleware
app.use(express.json({
verify: (req, res, buf) => {
try {
// Check if JSON is valid and meets schema requirements
validateSchema(buf.toString(), req.path);
} catch (e) {
throw new Error('Invalid JSON payload');
}
},
limit: '100kb' // Limit payload size
}));
```
### Monitoring and Logging
- Implement Comprehensive Logging
```csharp
// C# example of detailed security logging
public class SecurityLogger
{
private readonly ILogger _logger;
public SecurityLogger(ILogger logger)
{
_logger = logger;
}
public void LogAccessAttempt(string userId, string resourceId, bool success, AccessContext context)
{
var logEvent = new SecurityEvent
{
EventType = success ? "access_granted" : "access_denied",
Timestamp = DateTime.UtcNow,
UserId = userId,
ResourceId = resourceId,
IpAddress = context.IpAddress,
DeviceId = context.DeviceId,
DeviceHealth = context.DeviceHealthStatus,
Location = context.GeoLocation,
RequestedPermissions = context.RequestedPermissions,
RiskScore = context.RiskScore
};
// Log with appropriate level
if (success)
{
_logger.LogInformation("Access granted: {Event}", JsonSerializer.Serialize(logEvent));
}
else
{
_logger.LogWarning("Access denied: {Event}", JsonSerializer.Serialize(logEvent));
}
}
}
```
### Implement fine-grained network and application segmentation
```yaml
# Kubernetes Network Policy example for microsegmentation
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-backend-policy
namespace: production
spec:
podSelector:
matchLabels:
app: api-backend
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 443
egress:
- to:
- podSelector:
matchLabels:
app: database
ports:
- protocol: TCP
port: 5432
- to:
- namespaceSelector:
matchLabels:
name: monitoring
podSelector:
matchLabels:
app: telemetry
ports:
- protocol: TCP
port: 9090
```
================================================
FILE: sources/templates/custom-rule-template.md.example
================================================
---
description: Brief description of the rule
languages:
- python
- javascript
tags:
- data-security
alwaysApply: false
---
## Rule Title
Brief overview of what this rule enforces and why it matters.
### Section Name
- Guidance point with specific recommendation
- Another specific requirement or best practice
### Another Section
- Additional guidance organized by topic
- Keep points concise and actionable
### Implementation Checklist
- Verify requirement one is met
- Confirm requirement two is implemented
- Check that patterns are followed
### Test Plan
- Describe how to verify the rule is followed
- Include specific test scenarios
================================================
FILE: src/LICENSE.md
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
================================================
FILE: src/convert_to_ide_formats.py
================================================
# Copyright 2025 Cisco Systems, Inc. and its affiliates
#
# SPDX-License-Identifier: Apache-2.0
"""
Convert Unified Rules to IDE Formats
Transforms the unified markdown sources into IDE-specific bundles (Cursor,
Windsurf, Copilot, Agent Skills, Antigravity). This script is the main entry point
for producing distributable rule packs from the sources/ directory.
"""
import re
import shutil
from pathlib import Path
from collections import defaultdict
from converter import RuleConverter
from formats import (
CursorFormat,
WindsurfFormat,
CopilotFormat,
AgentSkillsFormat,
AntigravityFormat,
)
from utils import get_version_from_pyproject
from validate_versions import set_plugin_version, set_marketplace_version
# Project root is always one level up from src/
PROJECT_ROOT = Path(__file__).parent.parent
def sync_plugin_metadata(version: str) -> None:
"""
Sync version from pyproject.toml to Agent Skills metadata files.
Args:
version: Version string from pyproject.toml
"""
set_plugin_version(version, PROJECT_ROOT)
set_marketplace_version(version, PROJECT_ROOT)
print(f"✅ Synced plugin metadata to {version}")
def matches_tag_filter(rule_tags: list[str], filter_tags: list[str]) -> bool:
"""
Check if rule has all required tags (AND logic).
Args:
rule_tags: List of tags from the rule (already normalized to lowercase)
filter_tags: List of tags to filter by (already normalized to lowercase)
Returns:
True if rule has all filter tags (or no filter), False otherwise
"""
if not filter_tags:
return True # No filter means all pass
return all(tag in rule_tags for tag in filter_tags)
def update_skill_md(language_to_rules: dict[str, list[str]], skill_path: str) -> None:
"""
Update SKILL.md with language-to-rules mapping table.
Args:
language_to_rules: Dictionary mapping languages to rule files
skill_path: Path to SKILL.md file
"""
# Generate markdown table
table_lines = [
"| Language | Rule Files to Apply |",
"|----------|---------------------|",
]
for language in sorted(language_to_rules.keys()):
rules = sorted(language_to_rules[language])
rules_str = ", ".join(rules)
table_lines.append(f"| {language} | {rules_str} |")
table = "\n".join(table_lines)
# Markers for the language mappings section
start_marker = ""
end_marker = ""
# Read SKILL.md
skill_file = Path(skill_path)
content = skill_file.read_text(encoding="utf-8")
if start_marker not in content or end_marker not in content:
raise RuntimeError(
"Invalid template: Language mappings section not found in codeguard-SKILLS.md.template"
)
# Replace entire section including markers with just the table
start_idx = content.index(start_marker)
end_idx = content.index(end_marker) + len(end_marker)
new_section = f"\n\n{table}\n\n"
updated_content = content[:start_idx] + new_section + content[end_idx:]
# Write back to SKILL.md
skill_file.write_text(updated_content, encoding="utf-8")
print(f"Updated SKILL.md with language mappings")
def convert_rules(
input_path: str,
output_dir: str = "dist",
include_agentskills: bool = True,
version: str = None,
filter_tags: list[str] = None,
) -> dict[str, list[str]]:
"""
Convert rule file(s) to all supported IDE formats using RuleConverter.
Args:
input_path: Path to a single .md file or folder containing .md files
output_dir: Output directory (default: 'dist/')
include_agentskills: Whether to generate Agent Skills format (default: True, only for core rules)
version: Version string to use (default: read from pyproject.toml)
filter_tags: Optional list of tags to filter by (AND logic, case-insensitive)
Returns:
Dictionary with 'success' and 'errors' lists:
{
"success": ["rule1.md", "rule2.md"],
"errors": ["rule3.md: error message"]
}
Example:
results = convert_rules("sources/core", "dist", include_agentskills=True)
print(f"Converted {len(results['success'])} rules")
"""
if version is None:
version = get_version_from_pyproject()
# Specify formats to generate
all_formats = [
CursorFormat(version),
WindsurfFormat(version),
CopilotFormat(version),
AntigravityFormat(version),
]
# Only include Agent Skills format for core rules (committed as skills)
if include_agentskills:
all_formats.append(AgentSkillsFormat(version))
converter = RuleConverter(formats=all_formats)
path = Path(input_path)
if not path.exists():
raise FileNotFoundError(f"{input_path} does not exist")
# Determine files to process
if path.is_file():
if path.suffix != ".md":
raise ValueError(f"{input_path} is not a .md file")
md_files = [path]
else:
# Use rglob to recursively find all .md files in subdirectories
md_files = sorted(list(path.rglob("*.md")))
if not md_files:
raise ValueError(f"No .md files found in {input_path}")
print(f"Converting {len(md_files)} files from: {path}")
# Setup output directory
output_base = Path(output_dir)
results = {"success": [], "errors": [], "skipped": []}
language_to_rules = defaultdict(list)
# Process each file
for md_file in md_files:
try:
# Convert the file (raises exceptions on error)
result = converter.convert(md_file)
# Apply tag filter if specified
if filter_tags and not matches_tag_filter(result.tags, filter_tags):
results["skipped"].append(result.filename)
continue
# Write each format
output_files = []
for format_name, output in result.outputs.items():
# Construct output path
# Agent Skills goes to project root ./skills/
# Other formats go to dist/ (or specified output_dir)
if format_name == "agentskills":
base_dir = PROJECT_ROOT
else:
base_dir = output_base
output_file = (
base_dir / output.subpath / f"{result.basename}{output.extension}"
)
# Create directory if it doesn't exist and write file
output_file.parent.mkdir(parents=True, exist_ok=True)
output_file.write_text(output.content, encoding="utf-8")
output_files.append(output_file.name)
print(f"Success: {result.filename} → {', '.join(output_files)}")
results["success"].append(result.filename)
# Update language mappings for SKILL.md
for language in result.languages:
language_to_rules[language].append(result.filename)
except FileNotFoundError as e:
error_msg = f"{md_file.name}: File not found - {e}"
print(f"Error: {error_msg}")
results["errors"].append(error_msg)
except ValueError as e:
error_msg = f"{md_file.name}: Validation error - {e}"
print(f"Error: {error_msg}")
results["errors"].append(error_msg)
except Exception as e:
error_msg = f"{md_file.name}: Unexpected error - {e}"
print(f"Error: {error_msg}")
results["errors"].append(error_msg)
# Summary
if filter_tags:
print(
f"\nResults: {len(results['success'])} success, {len(results['skipped'])} skipped (tag filter), {len(results['errors'])} errors"
)
else:
print(
f"\nResults: {len(results['success'])} success, {len(results['errors'])} errors"
)
# Generate SKILL.md with language mappings (only if Agent Skills is included)
if include_agentskills and language_to_rules:
template_path = (
PROJECT_ROOT / "sources" / "core" / "codeguard-SKILLS.md.template"
)
if not template_path.exists():
raise FileNotFoundError(
f"SKILL.md template not found at {template_path}. "
"This file is required for Agent Skills generation."
)
output_skill_dir = PROJECT_ROOT / "skills" / "software-security"
output_skill_dir.mkdir(parents=True, exist_ok=True)
output_skill_path = output_skill_dir / "SKILL.md"
# Read template and inject current version from pyproject.toml
template_content = template_path.read_text(encoding="utf-8")
# Replace the hardcoded version with actual version
template_content = re.sub(
r'codeguard-version:\s*"[^"]*"',
f'codeguard-version: "{version}"',
template_content,
)
output_skill_path.write_text(template_content, encoding="utf-8")
update_skill_md(language_to_rules, str(output_skill_path))
return results
def _resolve_source_paths(args) -> list[Path]:
"""
Resolve source paths from CLI arguments.
Priority: --source flags > default (core)
"""
# If --source flags provided, resolve under sources/
if args.source:
return [Path("sources") / src for src in args.source]
# Default: core rules only
return [Path("sources/core")]
if __name__ == "__main__":
import sys
from argparse import ArgumentParser
parser = ArgumentParser(
description="Convert unified rule markdown into IDE-specific bundles."
)
parser.add_argument(
"--source",
nargs="+",
help="Named sources under ./sources to convert (e.g., --source core owasp). Default: core",
)
parser.add_argument(
"--output-dir",
"-o",
default="dist",
help="Output directory for generated bundles (default: dist).",
)
parser.add_argument(
"--tag",
"--tags",
dest="tags",
help="Filter rules by tags (comma-separated, case-insensitive, AND logic). Example: --tag api,web-security",
)
cli_args = parser.parse_args()
source_paths = _resolve_source_paths(cli_args)
# Validate all source paths exist
missing = [p for p in source_paths if not p.exists()]
if missing:
print(f"❌ Source path(s) not found: {', '.join(str(p) for p in missing)}")
sys.exit(1)
# Check for duplicate filenames across sources if multiple sources
if len(source_paths) > 1:
filename_to_sources = defaultdict(list)
for source_path in source_paths:
for md_file in source_path.rglob("*.md"):
filename_to_sources[md_file.name].append(source_path.name)
duplicates = {
name: srcs for name, srcs in filename_to_sources.items() if len(srcs) > 1
}
if duplicates:
print(f"❌ Found {len(duplicates)} duplicate filename(s) across sources:")
for filename, sources in duplicates.items():
print(f" - {filename} in: {', '.join(sources)}")
print("\nPlease rename files to have unique names across all sources.")
sys.exit(1)
# Get version once and sync to metadata files
version = get_version_from_pyproject()
sync_plugin_metadata(version)
# Check if core is in the sources for Agent Skills generation
has_core = Path("sources/core") in source_paths
if has_core:
# Validate template exists early
template_path = (
PROJECT_ROOT / "sources" / "core" / "codeguard-SKILLS.md.template"
)
if not template_path.exists():
print(f"❌ SKILL.md template not found at {template_path}")
print("This file is required for Agent Skills generation.")
sys.exit(1)
# Clean output directories once before processing
output_path = Path(cli_args.output_dir)
if output_path.exists():
shutil.rmtree(output_path)
print(f"✅ Cleaned {cli_args.output_dir}/ directory")
if has_core:
skills_rules_dir = PROJECT_ROOT / "skills" / "software-security" / "rules"
if skills_rules_dir.exists():
shutil.rmtree(skills_rules_dir)
print(f"✅ Cleaned skills/ directory")
# Print processing summary
if len(source_paths) > 1:
sources_list = ", ".join(p.name for p in source_paths)
print(f"\nConverting {len(source_paths)} sources: {sources_list}")
if has_core:
print("(Agent Skills will include only core rules)")
print()
# Convert all sources
aggregated = {"success": [], "errors": [], "skipped": []}
# Parse comma-separated tags and normalize to lowercase
filter_tags = None
if cli_args.tags:
filter_tags = [
tag.strip().lower() for tag in cli_args.tags.split(",") if tag.strip()
]
# Print tag filter info if active
if filter_tags:
print(
f"Tag filter active: {', '.join(filter_tags)} (AND logic - rules must have all tags)\n"
)
for source_path in source_paths:
is_core = source_path == Path("sources/core")
print(f"Processing: {source_path}")
results = convert_rules(
str(source_path),
cli_args.output_dir,
include_agentskills=is_core,
version=version,
filter_tags=filter_tags,
)
aggregated["success"].extend(results["success"])
aggregated["errors"].extend(results["errors"])
if "skipped" in results:
aggregated["skipped"].extend(results["skipped"])
print("")
if aggregated["errors"]:
print("❌ Some conversions failed")
sys.exit(1)
print("✅ All conversions successful")
================================================
FILE: src/converter.py
================================================
# Copyright 2025 Cisco Systems, Inc. and its affiliates
#
# SPDX-License-Identifier: Apache-2.0
"""
Rule Converter
Converts unified markdown rules to multiple IDE formats.
Handles parsing, validation, and format generation.
"""
from dataclasses import dataclass
from pathlib import Path
from language_mappings import languages_to_globs
from utils import parse_frontmatter_and_content, validate_tags
from formats import (
BaseFormat,
ProcessedRule,
)
@dataclass
class FormatOutput:
"""
Represents the output for a single format.
Attributes:
content: The fully formatted content with frontmatter
extension: File extension including dot (e.g., '.mdc')
subpath: Subdirectory path (e.g., '.cursor/rules', 'skills/software-security/rules')
"""
content: str
extension: str
subpath: str
@dataclass
class ConversionResult:
"""
Represents the complete result of converting a rule file.
Attributes:
filename: Original filename (e.g., 'my-rule.md')
basename: Filename without extension (e.g., 'my-rule')
outputs: Dictionary mapping format names to their outputs
languages: List of programming languages the rule applies to, empty list if always applies
tags: List of tags for categorizing and filtering rules
Example:
result = ConversionResult(
filename="my-rule.md",
basename="my-rule",
outputs={
"cursor": FormatOutput(
content="---\\n...\\n---\\n\\nContent",
extension=".mdc",
subpath=".cursor/rules"
)
},
languages=["python", "javascript"],
tags=["authentication", "web-security"]
)
"""
filename: str
basename: str
outputs: dict[str, FormatOutput]
languages: list[str]
tags: list[str]
class RuleConverter:
"""
Converts markdown rules to multiple IDE formats.
Uses the BaseFormat abstraction to support multiple IDE formats in an extensible way.
New formats can be added by creating a new BaseFormat subclass and passing it to the converter.
Main Methods:
- parse_rule(): Parse markdown file with YAML frontmatter
- generate_globs(): Convert languages to glob patterns
- convert(): Convert a rule file to all registered formats (returns ConversionResult)
Example:
# Create converter
from converter import RuleConverter, ConversionResult, FormatOutput
from formats import CursorFormat, WindsurfFormat
from utils import get_version_from_pyproject
version = get_version_from_pyproject()
converter = RuleConverter(formats=[
CursorFormat(version),
WindsurfFormat(version)
])
# Convert a file
try:
result = converter.convert("rule.md")
# result is ConversionResult dataclass
for format_name, output in result.outputs.items():
# output is FormatOutput dataclass
print(f"{format_name}: {output.extension}")
save_file(output.content, output.subpath)
except ValueError as e:
print(f"Invalid rule: {e}")
"""
def __init__(self, formats: list[BaseFormat]):
"""
Initialize the converter with version info and supported formats.
Args:
formats: List of BaseFormat instances to use for conversion.
"""
self.formats = formats
def parse_rule(self, content: str, filename: str) -> ProcessedRule:
"""
Parse a markdown file with required frontmatter.
Args:
content: Full file content with YAML frontmatter
filename: Name of the file being parsed
Returns:
ProcessedRule with validated frontmatter and content
Raises:
ValueError: If frontmatter is missing or invalid
"""
# Parse frontmatter and content using shared utility
frontmatter, markdown_content = parse_frontmatter_and_content(content)
if not frontmatter:
raise ValueError(f"Missing or invalid frontmatter in {filename}")
# Validate required description field
if "description" not in frontmatter or not frontmatter["description"].strip():
raise ValueError(f"Missing required 'description' field in {filename}")
always_apply = frontmatter.get("alwaysApply", False)
# Validate languages field based on alwaysApply setting
if always_apply:
# If alwaysApply is true, languages should not be specified or should be empty
if "languages" in frontmatter and frontmatter["languages"]:
raise ValueError(
f"When 'alwaysApply' is true, 'languages' should not be specified or should be empty in {filename}"
)
languages = [] # No languages when always applying
else:
# If alwaysApply is false, languages is required
if "languages" not in frontmatter:
raise ValueError(
f"Missing required 'languages' field in {filename} (required when alwaysApply is false)"
)
languages = frontmatter["languages"]
if not isinstance(languages, list) or not languages:
raise ValueError(
f"'languages' must be a non-empty list in {filename} when alwaysApply is false"
)
# Parse and validate tags (optional field)
tags = []
if "tags" in frontmatter:
tags = validate_tags(frontmatter["tags"], filename)
# Adding rule_id to the beginning of the content
rule_id = Path(filename).stem
markdown_content = f"rule_id: {rule_id}\n\n{markdown_content}"
return ProcessedRule(
description=frontmatter["description"],
languages=[lang.lower() for lang in languages],
always_apply=always_apply,
content=markdown_content,
filename=filename,
tags=tags,
)
def generate_globs(self, languages: list[str]) -> str:
"""
Generate comma-separated glob patterns for languages.
Args:
languages: List of programming languages
Returns:
Comma-separated glob patterns, or "**/*" for all files
"""
# Use shared function from language_mappings
globs = languages_to_globs(languages)
return globs if globs else "**/*"
def convert(self, filepath: str) -> ConversionResult:
"""
Convert a rule file to all registered formats.
This method handles the entire conversion pipeline:
- Reading the file
- Parsing and validating
- Generating all format outputs
Args:
filepath: Path to the rule file to convert (str or Path)
Returns:
ConversionResult with filename, basename, and format outputs
Raises:
FileNotFoundError: If the rule file doesn't exist
ValueError: If the rule has invalid frontmatter or structure
Exception: For other unexpected errors during conversion
Example:
try:
result = converter.convert("rules/my-rule.md")
for format_name, output in result.outputs.items():
path = f"{output.subpath}/{result.basename}{output.extension}"
write_file(path, output.content)
except (FileNotFoundError, ValueError) as e:
print(f"Error: {e}")
"""
filepath = Path(filepath)
filename = filepath.name
basename = filepath.stem
# Read the rule file (may raise FileNotFoundError)
content = filepath.read_text(encoding="utf-8")
# Parse and validate (may raise ValueError)
rule = self.parse_rule(content, filename)
# Generate globs once for all formats
globs = self.generate_globs(rule.languages)
# Generate output for each format
outputs = {}
for format_handler in self.formats:
format_name = format_handler.get_format_name()
outputs[format_name] = FormatOutput(
content=format_handler.generate(rule, globs),
extension=format_handler.get_file_extension(),
subpath=format_handler.get_output_subpath(),
)
return ConversionResult(
filename=filename,
basename=basename,
outputs=outputs,
languages=rule.languages,
tags=rule.tags,
)
================================================
FILE: src/formats/__init__.py
================================================
# Copyright 2025 Cisco Systems, Inc. and its affiliates
#
# SPDX-License-Identifier: Apache-2.0
"""
Formats Package
This package contains all IDE format implementations for rule conversion.
Available Formats:
- CursorFormat: Generates .mdc files for Cursor IDE
- WindsurfFormat: Generates .md files for Windsurf IDE
- CopilotFormat: Generates .instructions.md files for GitHub Copilot
- AgentSkillsFormat: Generates .md files for Agent Skills (OpenAI Codex, Claude Code, other AI coding tools)
- AntigravityFormat: Generates .md files for Google Antigravity
Usage:
from formats import BaseFormat, ProcessedRule, CursorFormat, WindsurfFormat, CopilotFormat, AgentSkillsFormat, AntigravityFormat
version = "1.0.0"
formats = [
CursorFormat(version),
WindsurfFormat(version),
CopilotFormat(version),
AgentSkillsFormat(version),
AntigravityFormat(version),
]
"""
from formats.base import BaseFormat, ProcessedRule
from formats.cursor import CursorFormat
from formats.windsurf import WindsurfFormat
from formats.copilot import CopilotFormat
from formats.agentskills import AgentSkillsFormat
from formats.antigravity import AntigravityFormat
__all__ = [
"BaseFormat",
"ProcessedRule",
"CursorFormat",
"WindsurfFormat",
"CopilotFormat",
"AgentSkillsFormat",
"AntigravityFormat",
]
================================================
FILE: src/formats/agentskills.py
================================================
# Copyright 2025 Cisco Systems, Inc. and its affiliates
#
# SPDX-License-Identifier: Apache-2.0
"""
Agent Skills Format Implementation
Generates .md files for the Agent Skills standard (agentskills.io).
This format is used by OpenAI Codex, Claude Code, and other AI coding tools.
"""
from formats.base import BaseFormat, ProcessedRule
class AgentSkillsFormat(BaseFormat):
"""
Agent Skills format implementation (.md files).
Agent Skills (https://agentskills.io/) is an open standard for extending
AI coding agents with task-specific capabilities. It uses standard markdown
files with YAML frontmatter to define rules and instructions.
This format is adopted by:
- OpenAI Codex (skills)
- Claude Code (plugins)
- Other AI coding tools
The original rule content is preserved and placed in the
skills/software-security/rules/ directory for distribution.
"""
def get_format_name(self) -> str:
"""Return Agent Skills format identifier."""
return "agentskills"
def get_file_extension(self) -> str:
"""Return Agent Skills format file extension."""
return ".md"
def get_output_subpath(self) -> str:
"""Return Agent Skills output subdirectory."""
return "skills/software-security/rules"
def generate(self, rule: ProcessedRule, globs: str) -> str:
"""
Generate Agent Skills .md format.
Agent Skills should preserve the original YAML frontmatter
(description, languages, alwaysApply) so the rules remain complete
and can be referenced properly by AI coding agents.
Args:
rule: The processed rule to format
globs: Glob patterns (not used for Agent Skills format)
Returns:
Complete markdown with original YAML frontmatter preserved
"""
# Build YAML frontmatter
yaml_lines = []
# Add description
desc = self._format_yaml_field("description", rule.description)
if desc:
yaml_lines.append(desc)
# Add languages if present
if rule.languages:
# Format as YAML list
yaml_lines.append("languages:")
for lang in rule.languages:
yaml_lines.append(f"- {lang}")
# Add alwaysApply
yaml_lines.append(f"alwaysApply: {str(rule.always_apply).lower()}")
return self._build_yaml_frontmatter(yaml_lines, rule.content)
================================================
FILE: src/formats/antigravity.py
================================================
# Copyright 2025 Cisco Systems, Inc. and its affiliates
#
# SPDX-License-Identifier: Apache-2.0
"""
Antigravity Format Implementation
Generates .md rule files for Antigravity with YAML frontmatter.
"""
from formats.base import BaseFormat, ProcessedRule
class AntigravityFormat(BaseFormat):
"""
Antigravity format implementation (.md rule files).
Antigravity uses .md files with YAML frontmatter containing:
- trigger: 'always_on' or 'glob' (activation type)
- globs: (if trigger is 'glob') File matching patterns
- description: Rule description
- version: Rule version
Rules use activation types (Always On or Glob) to determine when
they apply, similar to Windsurf's implementation.
See: https://antigravity.google/docs/rules-workflows
"""
def get_format_name(self) -> str:
"""Return Antigravity format identifier."""
return "antigravity"
def get_file_extension(self) -> str:
"""Return Antigravity format file extension."""
return ".md"
def get_output_subpath(self) -> str:
"""Return Antigravity output subdirectory."""
return ".agent/rules"
def generate(self, rule: ProcessedRule, globs: str) -> str:
"""
Generate Antigravity .md format with YAML frontmatter.
Args:
rule: The processed rule to format
globs: Glob patterns for file matching
Returns:
Formatted .md content with trigger, globs, description, and version
Note:
Antigravity rules use activation types:
- 'always_on': Rule applies to all files (when alwaysApply is true)
- 'glob': Rule applies to files matching glob patterns (language-specific)
"""
yaml_lines = []
# Use trigger: always_on for rules that should always apply
if rule.always_apply:
yaml_lines.append("trigger: always_on")
else:
yaml_lines.append("trigger: glob")
yaml_lines.append(f"globs: {globs}")
# Add description (required by Antigravity spec)
desc = self._format_yaml_field("description", rule.description)
if desc:
yaml_lines.append(desc)
# Add version
yaml_lines.append(f"version: {self.version}")
return self._build_yaml_frontmatter(yaml_lines, rule.content)
================================================
FILE: src/formats/base.py
================================================
# Copyright 2025 Cisco Systems, Inc. and its affiliates
#
# SPDX-License-Identifier: Apache-2.0
"""
Base Format Class
Abstract base class for all IDE rule formats.
Defines the interface that all format implementations must follow.
"""
import yaml
from abc import ABC, abstractmethod
from dataclasses import dataclass
@dataclass
class ProcessedRule:
"""
Represents a processed rule with required frontmatter.
Attributes:
description: Human-readable description of the rule
languages: List of programming languages this rule applies to
always_apply: Whether this rule should apply to all files
content: The actual rule content in markdown format
filename: Original filename of the rule
tags: List of tags for categorizing and filtering rules
"""
description: str
languages: list[str]
always_apply: bool
content: str
filename: str
tags: list[str]
class BaseFormat(ABC):
"""
Abstract base class for IDE rule formats.
This class defines the interface that all format implementations must follow.
Each format is responsible for:
- Providing its file extension (e.g., '.mdc', '.md')
- Providing its output subdirectory path (e.g., '.cursor/rules')
- Generating formatted content with proper frontmatter
"""
def __init__(self, version: str):
"""
Initialize format with version information.
Args:
version: Version string to include in generated files
"""
self.version = version
@abstractmethod
def get_format_name(self) -> str:
"""
Return the unique identifier for this format.
Returns:
Format name (e.g., 'cursor', 'windsurf', 'copilot')
"""
pass
@abstractmethod
def get_file_extension(self) -> str:
"""
Return the file extension for this format.
Returns:
File extension including the dot (e.g., '.mdc', '.md')
"""
pass
@abstractmethod
def get_output_subpath(self) -> str:
"""
Return the subdirectory path for this format.
Returns:
Subdirectory path (e.g., '.cursor/rules', 'skills/software-security/rules')
"""
pass
@abstractmethod
def generate(self, rule: ProcessedRule, globs: str) -> str:
"""
Generate the formatted content for this IDE format.
Args:
rule: The processed rule to format
globs: Glob patterns for file matching
Returns:
Fully formatted content with frontmatter and rule content
"""
pass
def _build_yaml_frontmatter(self, lines: list[str], content: str) -> str:
"""
Helper to build complete file with YAML frontmatter.
Args:
lines: List of YAML lines to include in frontmatter
content: The markdown content to append after frontmatter
Returns:
Complete formatted string with frontmatter and content
"""
yaml_str = "\n".join(lines)
return f"---\n{yaml_str}\n---\n\n{content}\n"
def _format_yaml_field(self, field_name: str, value: str) -> str:
"""
Format a field with proper YAML escaping for special characters.
Args:
field_name: Name of the YAML field
value: Value to format
Returns:
Properly formatted YAML string, or empty string if value is empty
"""
if value and value.strip():
yaml_dump = yaml.safe_dump(
{field_name: value},
default_flow_style=False,
allow_unicode=True,
width=float("inf")
)
return yaml_dump.strip()
return ""
================================================
FILE: src/formats/copilot.py
================================================
# Copyright 2025 Cisco Systems, Inc. and its affiliates
#
# SPDX-License-Identifier: Apache-2.0
"""
Copilot Format Implementation
Generates .instructions.md files for GitHub Copilot with YAML frontmatter.
"""
from formats.base import BaseFormat, ProcessedRule
class CopilotFormat(BaseFormat):
"""
GitHub Copilot format implementation (.instructions.md files).
Copilot uses .instructions.md files with YAML frontmatter containing:
- applyTo: File matching patterns
- title: Rule title/description
- version: Rule version
"""
def get_format_name(self) -> str:
"""Return Copilot format identifier."""
return "copilot"
def get_file_extension(self) -> str:
"""Return Copilot format file extension."""
return ".instructions.md"
def get_output_subpath(self) -> str:
"""Return Copilot output subdirectory."""
return ".github/instructions"
def generate(self, rule: ProcessedRule, globs: str) -> str:
"""
Generate Copilot .instructions.md format with YAML frontmatter.
Args:
rule: The processed rule to format
globs: Glob patterns for file matching
Returns:
Formatted .instructions.md content
"""
yaml_lines = []
# Add applyTo (Copilot's equivalent of globs)
yaml_lines.append(f"applyTo: '{globs}'")
# Add description
description = self._format_yaml_field("description", rule.description)
if description:
yaml_lines.append(description)
# Add version
yaml_lines.append(f"version: {self.version}")
return self._build_yaml_frontmatter(yaml_lines, rule.content)
================================================
FILE: src/formats/cursor.py
================================================
# Copyright 2025 Cisco Systems, Inc. and its affiliates
#
# SPDX-License-Identifier: Apache-2.0
"""
Cursor Format Implementation
Generates .mdc files for Cursor IDE with YAML frontmatter.
"""
from formats.base import BaseFormat, ProcessedRule
class CursorFormat(BaseFormat):
"""
Cursor IDE format implementation (.mdc files).
Cursor uses .mdc files with YAML frontmatter containing:
- description: Rule description
- globs: File matching patterns
- version: Rule version
- alwaysApply: (optional) Whether to apply to all files
"""
def get_format_name(self) -> str:
"""Return Cursor format identifier."""
return "cursor"
def get_file_extension(self) -> str:
"""Return Cursor format file extension."""
return ".mdc"
def get_output_subpath(self) -> str:
"""Return Cursor output subdirectory."""
return ".cursor/rules"
def generate(self, rule: ProcessedRule, globs: str) -> str:
"""
Generate Cursor .mdc format with YAML frontmatter.
Args:
rule: The processed rule to format
globs: Glob patterns for file matching
Returns:
Formatted .mdc content
"""
yaml_lines = []
# Add description if present
desc = self._format_yaml_field("description", rule.description)
if desc:
yaml_lines.append(desc)
# Add globs and version
yaml_lines.append(f"globs: {globs}")
yaml_lines.append(f"version: {self.version}")
# Add alwaysApply if needed
if rule.always_apply:
yaml_lines.append("alwaysApply: true")
return self._build_yaml_frontmatter(yaml_lines, rule.content)
================================================
FILE: src/formats/windsurf.py
================================================
# Copyright 2025 Cisco Systems, Inc. and its affiliates
#
# SPDX-License-Identifier: Apache-2.0
"""
Windsurf Format Implementation
Generates .md files for Windsurf IDE with YAML frontmatter.
"""
from formats.base import BaseFormat, ProcessedRule
class WindsurfFormat(BaseFormat):
"""
Windsurf IDE format implementation (.md files).
Windsurf uses .md files with YAML frontmatter containing:
- trigger: 'always_on' or 'glob'
- globs: (if trigger is 'glob') File matching patterns
- title: Rule title/description
- version: Rule version
"""
def get_format_name(self) -> str:
"""Return Windsurf format identifier."""
return "windsurf"
def get_file_extension(self) -> str:
"""Return Windsurf format file extension."""
return ".md"
def get_output_subpath(self) -> str:
"""Return Windsurf output subdirectory."""
return ".windsurf/rules"
def generate(self, rule: ProcessedRule, globs: str) -> str:
"""
Generate Windsurf .md format with YAML frontmatter.
Args:
rule: The processed rule to format
globs: Glob patterns for file matching
Returns:
Formatted .md content
"""
yaml_lines = []
# Use trigger: always_on for rules that should always apply
if rule.always_apply:
yaml_lines.append("trigger: always_on")
else:
yaml_lines.append("trigger: glob")
yaml_lines.append(f"globs: {globs}")
# Add title (Windsurf uses 'title' instead of 'description')
title = self._format_yaml_field("title", rule.description)
if title:
yaml_lines.append(title)
# Add version
yaml_lines.append(f"version: {self.version}")
return self._build_yaml_frontmatter(yaml_lines, rule.content)
================================================
FILE: src/language_mappings.py
================================================
# Copyright 2025 Cisco Systems, Inc. and its affiliates
#
# SPDX-License-Identifier: Apache-2.0
"""
Shared language mappings for all rule tools.
Single source of truth for language-to-extension mappings.
"""
# Master mapping of languages to file extensions
LANGUAGE_TO_EXTENSIONS = {
"apex": [".cls", ".trigger"],
"python": [".py", ".pyx", ".pyi"],
"javascript": [".js", ".jsx", ".mjs"],
"typescript": [".ts", ".tsx"],
"java": [".java"],
"c": [".c", ".h"],
"cpp": [".cpp", ".hpp", ".cc", ".cxx"],
"c++": [".cpp", ".hpp", ".cc", ".cxx"], # Alias
"go": [".go"],
"rust": [".rs"],
"ruby": [".rb"],
"php": [".php"],
"swift": [".swift"],
"kotlin": [".kt", ".kts"],
"scala": [".scala"],
"r": [".r", ".R"],
"matlab": [".m"],
"julia": [".jl"],
"dart": [".dart"],
"lua": [".lua"],
"perl": [".pl", ".pm"],
"shell": [".sh", ".bash"],
"powershell": [".ps1"],
"fsharp": [".fs", ".fsx"],
"clojure": [".clj", ".cljs"],
"elixir": [".ex", ".exs"],
"erlang": [".erl", ".hrl"],
"ocaml": [".ml", ".mli"],
"nim": [".nim"],
"vlang": [".v"],
"zig": [".zig"],
"d": [".d"],
"solidity": [".sol"],
"vyper": [".vy"],
"cairo": [".cairo"],
"sway": [".sway"],
"handlebars": [".hbs"],
"liquid": [".liquid"],
"markdown": [".md"],
"mdx": [".mdx"],
"latex": [".tex"],
"yaml": [".yml", ".yaml"],
"docker": ["Dockerfile*", "docker-compose*", ".dockerfile"],
"xml": [".xml", ".xsd", ".xslt", ".wsdl"],
"vue": [".vue"],
"svelte": [".svelte"],
"astro": [".astro"],
"elm": [".elm"],
"purescript": [".purs"],
"idris": [".idr"],
"agda": [".agda"],
"lean": [".lean"],
"coq": [".coq"],
"verilog": [".v"],
"vhdl": [".vhd", ".vhdl"],
"cuda": [".cu", ".cuh"],
"opencl": [".cl"],
"glsl": [".glsl", ".vert", ".frag"],
"hlsl": [".hlsl"],
"wgsl": [".wgsl"],
"html": [".html", ".htm"],
"sql": [".sql", ".ddl", ".dml"],
}
# Reverse mapping: extension to language (for conversion from globs)
EXTENSION_TO_LANGUAGE = {}
for lang, exts in LANGUAGE_TO_EXTENSIONS.items():
for ext in exts:
# First language wins for duplicate extensions
if ext not in EXTENSION_TO_LANGUAGE:
EXTENSION_TO_LANGUAGE[ext] = lang
def languages_to_globs(languages: list[str]) -> str:
"""
Convert list of languages to glob patterns.
Args:
languages: List of programming language names (e.g., ['python', 'javascript'])
Returns:
Comma-separated glob patterns (e.g., '**/*.py,**/*.js')
Empty string if no languages provided
"""
if not languages:
return ""
extensions = []
for lang in languages:
if lang in LANGUAGE_TO_EXTENSIONS:
for ext in LANGUAGE_TO_EXTENSIONS[lang]:
if "*" in ext:
extensions.append(ext)
else:
extensions.append(f"**/*{ext}")
return ",".join(sorted(set(extensions)))
def globs_to_languages(globs: str) -> list[str]:
"""
Convert glob patterns to list of languages.
Args:
globs: Comma-separated glob patterns (e.g., '**/*.py,**/*.js')
Returns:
Sorted list of language names that match the glob patterns
Empty list if no patterns or universal glob provided
"""
if not globs or globs in ["**", "*", "**/*"]:
return []
languages = set()
patterns = globs.split(",")
for pattern in patterns:
pattern = pattern.strip().lower()
# Check for file extensions and patterns
for ext, lang in EXTENSION_TO_LANGUAGE.items():
if ext.lower() in pattern:
languages.add(lang)
break # One match per pattern is enough
return sorted(languages)
================================================
FILE: src/tag_mappings.py
================================================
# Copyright 2025 Cisco Systems, Inc. and its affiliates
#
# SPDX-License-Identifier: Apache-2.0
"""
Tag Mappings
Centralized list of known tags for categorizing security rules.
"""
# Known tags used in rules
# Add new tags here as they are introduced in rules
KNOWN_TAGS = {
"authentication",
"data-security",
"infrastructure",
"privacy",
"secrets",
"web",
}
================================================
FILE: src/utils.py
================================================
# Copyright 2025 Cisco Systems, Inc. and its affiliates
#
# SPDX-License-Identifier: Apache-2.0
"""
Utilities for rule processing.
Common utilities used across the rule conversion tools.
"""
import re
import tomllib
from pathlib import Path
import yaml
def parse_frontmatter_and_content(content: str) -> tuple[dict | None, str]:
"""
Parse YAML frontmatter and content from markdown.
Frontmatter must be in the format:
---
yaml content
---
markdown content
The closing --- must be on its own line (not part of a comment or text).
Args:
content: Full file content
Returns:
Tuple of (frontmatter dict, markdown content)
Returns (None, content) if no valid frontmatter found
"""
if not content.startswith("---\n"):
return None, content
# Look for closing --- on its own line
# Use regex to ensure --- is at start of line (after newline)
closing_pattern = re.compile(r'\n---\n')
match = closing_pattern.search(content)
if not match:
# No proper closing ---, treat as no frontmatter
return None, content
# Extract frontmatter between opening and closing ---
frontmatter_text = content[4:match.start()] # Skip opening "---\n"
markdown_content = content[match.end():] # Skip closing "---\n"
try:
frontmatter = yaml.safe_load(frontmatter_text)
except yaml.YAMLError:
return None, content
return frontmatter, markdown_content.strip()
def validate_tags(tags, filename=None) -> list[str]:
"""
Validate tags list and return normalized (lowercase) tags.
Args:
tags: The tags value to validate (should be a non-empty list)
filename: Optional filename for better error messages
Returns:
List of normalized (lowercase) tags with duplicates removed.
Original order is preserved.
Raises:
ValueError: If tags are invalid (wrong type, empty list, contain whitespace, etc.)
Note:
- An empty tags list (tags: []) is considered invalid. If you have no tags,
omit the 'tags' field entirely from the frontmatter.
- Duplicate tags (after normalization) are automatically removed while
preserving the order of first occurrence.
"""
context = f" in {filename}" if filename else ""
if not isinstance(tags, list):
raise ValueError(f"'tags' must be a list{context}")
if not tags:
raise ValueError(f"'tags' list cannot be empty{context}. Omit the field if you have no tags.")
normalized = []
for tag in tags:
if not isinstance(tag, str):
raise ValueError(f"All tags must be strings{context}, found: {type(tag).__name__}")
if any(c.isspace() for c in tag):
raise ValueError(f"Tags cannot contain whitespace: '{tag}'{context}")
if not tag:
raise ValueError(f"Empty tag found{context}")
normalized.append(tag.lower())
return list(dict.fromkeys(normalized))
def get_version_from_pyproject() -> str:
"""
Read version from pyproject.toml using Python's built-in TOML parser.
Requires Python 3.11+ for tomllib support.
Returns:
Version string from pyproject.toml
Raises:
FileNotFoundError: If pyproject.toml is not found
ValueError: If version field is missing or invalid
"""
pyproject_path = Path("pyproject.toml")
if not pyproject_path.exists():
raise FileNotFoundError("pyproject.toml not found")
try:
with open(pyproject_path, "rb") as f:
data = tomllib.load(f)
if "project" in data and "version" in data["project"]:
version = data["project"]["version"]
if isinstance(version, str) and version.strip():
return version.strip()
raise ValueError("Version field not found in pyproject.toml [project] section")
except tomllib.TOMLDecodeError as e:
raise ValueError(f"Invalid TOML syntax in pyproject.toml: {str(e)}")
except (FileNotFoundError, ValueError):
raise
except Exception as e:
raise ValueError(f"Unexpected error reading pyproject.toml: {str(e)}")
================================================
FILE: src/validate_unified_rules.py
================================================
# Copyright 2025 Cisco Systems, Inc. and its affiliates
#
# SPDX-License-Identifier: Apache-2.0
"""
Validate Unified Rules Format
Validates that unified rules have correct YAML frontmatter and structure.
"""
import sys
from pathlib import Path
from language_mappings import LANGUAGE_TO_EXTENSIONS
from tag_mappings import KNOWN_TAGS
from utils import parse_frontmatter_and_content, validate_tags
def validate_rule(file_path: Path) -> dict[str, list[str]]:
"""Validate a single unified rule file."""
errors = []
warnings = []
try:
# Read and parse file
content = file_path.read_text(encoding="utf-8")
frontmatter, markdown_content = parse_frontmatter_and_content(content)
if frontmatter is None:
errors.append("Missing or invalid YAML frontmatter")
return {"errors": errors, "warnings": warnings}
# Check required fields
if "description" not in frontmatter:
errors.append("Missing required field: description")
elif not str(frontmatter["description"]).strip():
errors.append("description cannot be empty")
# Validate languages and alwaysApply logic
has_languages = "languages" in frontmatter and frontmatter["languages"]
always_apply = frontmatter.get("alwaysApply", False)
if always_apply and has_languages:
errors.append("Rules with alwaysApply=true should not have languages")
elif not always_apply and not has_languages:
errors.append("Rules must have either languages or alwaysApply=true")
# Validate language names if present
if has_languages and isinstance(frontmatter["languages"], list):
unknown = [
lang
for lang in frontmatter["languages"]
if lang.lower() not in LANGUAGE_TO_EXTENSIONS
]
if unknown:
warnings.append(f"Unknown languages: {', '.join(unknown)}")
# Validate tags if present
if "tags" in frontmatter:
try:
normalized_tags = validate_tags(frontmatter["tags"], file_path.name)
# Error on tags not in known list
unknown_tags = [tag for tag in normalized_tags if tag not in KNOWN_TAGS]
if unknown_tags:
errors.append(f"Unknown tags (add to KNOWN_TAGS): {', '.join(sorted(unknown_tags))}")
except ValueError as e:
errors.append(str(e))
# Check content exists
if not markdown_content.strip():
errors.append("Rule content cannot be empty")
except Exception as e:
errors.append(f"Error reading file: {str(e)}")
return {"errors": errors, "warnings": warnings}
def main():
"""Validate all rules in the sources directory."""
rules_dir = Path(sys.argv[1] if len(sys.argv) > 1 else "sources")
if not rules_dir.exists():
print(f"❌ Directory {rules_dir} does not exist")
sys.exit(1)
# Find all .md files recursively (excluding README and templates)
md_files = [
f for f in rules_dir.rglob("*.md")
if f.name.lower() != "readme.md" and not f.name.endswith(".template")
]
if not md_files:
print(f"❌ No rule files found in {rules_dir}")
sys.exit(1)
print(f"🔍 Validating {len(md_files)} rules in {rules_dir} (recursive)\n")
passed = 0
failed = 0
total_warnings = 0
for md_file in sorted(md_files):
result = validate_rule(md_file)
errors = result["errors"]
warnings = result["warnings"]
if errors:
failed += 1
print(f"❌ {md_file.name}")
for error in errors:
print(f" - {error}")
else:
passed += 1
if warnings:
print(f"✅ {md_file.name}")
for warning in warnings:
print(f" ⚠️ {warning}")
total_warnings += 1
else:
print(f"✅ {md_file.name}")
# Summary
print(f"\n📊 Results: {passed} passed, {failed} failed")
if total_warnings:
print(f" Warnings: {total_warnings}")
if failed > 0:
print("\n❌ Validation failed")
sys.exit(1)
else:
print("\n✅ All rules valid!")
if __name__ == "__main__":
main()
================================================
FILE: src/validate_versions.py
================================================
#!/usr/bin/env python3
# Copyright 2025 Cisco Systems, Inc. and its affiliates
#
# SPDX-License-Identifier: Apache-2.0
"""
Version Validation Script
Validates that all version strings match across:
- pyproject.toml
- .claude-plugin/plugin.json
- .claude-plugin/marketplace.json
"""
import json
import re
import sys
import tomllib
from pathlib import Path
from typing import NamedTuple
class VersionCheck(NamedTuple):
"""Result of a version check."""
file: str
expected: str
found: str
matches: bool
def get_pyproject_version(root: Path) -> str:
"""Get version from pyproject.toml."""
pyproject_path = root / "pyproject.toml"
with open(pyproject_path, "rb") as f:
data = tomllib.load(f)
return data["project"]["version"]
def get_plugin_version(root: Path) -> str:
"""Get version from plugin.json."""
plugin_path = root / ".claude-plugin" / "plugin.json"
with open(plugin_path, encoding="utf-8") as f:
data = json.load(f)
return data["version"]
def set_plugin_version(version: str, root: Path) -> None:
"""Set version in plugin.json."""
plugin_path = root / ".claude-plugin" / "plugin.json"
with open(plugin_path, encoding="utf-8") as f:
data = json.load(f)
data["version"] = version
with open(plugin_path, "w", encoding="utf-8") as f:
json.dump(data, f, indent=2)
f.write("\n")
def get_marketplace_version(root: Path) -> str:
"""Get version from marketplace.json."""
marketplace_path = root / ".claude-plugin" / "marketplace.json"
with open(marketplace_path, encoding="utf-8") as f:
data = json.load(f)
return data["plugins"][0]["version"]
def set_marketplace_version(version: str, root: Path) -> None:
"""Set version in marketplace.json."""
marketplace_path = root / ".claude-plugin" / "marketplace.json"
with open(marketplace_path, encoding="utf-8") as f:
data = json.load(f)
for plugin in data.get("plugins", []):
plugin["version"] = version
with open(marketplace_path, "w", encoding="utf-8") as f:
json.dump(data, f, indent=2)
f.write("\n")
def _read_front_matter_value(path: Path, key: str) -> str:
"""Read a YAML front-matter value from a markdown file."""
content = path.read_text(encoding="utf-8")
front_matter_match = re.match(r"^---\s*\n(.*?)\n---\s*\n", content, re.DOTALL)
if not front_matter_match:
raise ValueError(f"Missing front matter in {path}")
front_matter = front_matter_match.group(1)
value_match = re.search(
rf'^{re.escape(key)}:\s*"([^"]+)"\s*$',
front_matter,
re.MULTILINE,
)
if not value_match:
raise ValueError(f"Missing {key} in front matter for {path}")
return value_match.group(1)
def get_skill_codeguard_version(root: Path) -> str:
"""Get codeguard-version from skills/software-security/SKILL.md."""
skill_path = root / "skills" / "software-security" / "SKILL.md"
return _read_front_matter_value(skill_path, "codeguard-version")
def validate_versions(expected_version: str, root: Path = None) -> list[VersionCheck]:
"""
Validate all versions match the expected version.
Args:
expected_version: The version to validate against (e.g., from git tag)
root: Project root directory (defaults to parent of this script)
Returns:
List of VersionCheck results
"""
if root is None:
root = Path(__file__).parent.parent
checks = [
VersionCheck(
"pyproject.toml", expected_version, get_pyproject_version(root), False
),
VersionCheck("plugin.json", expected_version, get_plugin_version(root), False),
VersionCheck(
"marketplace.json", expected_version, get_marketplace_version(root), False
),
VersionCheck(
"SKILL.md",
expected_version,
get_skill_codeguard_version(root),
False,
),
]
# Update matches field
return [
VersionCheck(c.file, c.expected, c.found, c.expected == c.found) for c in checks
]
def main() -> int:
"""Main entry point for CLI."""
if len(sys.argv) != 2:
print("Usage: validate_versions.py ")
print("Example: validate_versions.py 1.0.0")
return 1
expected_version = sys.argv[1]
results = validate_versions(expected_version)
# Print results
all_match = True
for check in results:
if check.matches:
print(f"✅ {check.file}: {check.found}")
else:
print(f"❌ {check.file}: expected {check.expected}, found {check.found}")
all_match = False
if all_match:
print(f"\n✅ All versions match: {expected_version}")
return 0
else:
print(f"\n❌ Version mismatch detected!")
return 1
if __name__ == "__main__":
sys.exit(main())