secure-development
SKILL.md
Secure Development Skill
Purpose
This skill ensures all code development follows security-by-design principles as defined in the Hack23 ISMS Secure Development Policy. It applies to all software development activities including web applications, APIs, infrastructure code, and scripts.
Rules
Input Validation
MUST:
- Validate ALL user input at the point of entry (server-side validation is mandatory)
- Use allowlist validation (define what IS allowed, not what ISN'T)
- Validate data type, length, format, and range
- Encode output before rendering to prevent XSS
- Sanitize input before use in queries, commands, or file operations
- Reject invalid input with clear error messages (without exposing system details)
MUST NOT:
- Rely solely on client-side validation
- Trust data from external sources (APIs, databases, files) without validation
- Use blocklist validation as the primary defense
- Echo raw user input back to the browser
- Expose stack traces or system information in error messages
Authentication and Authorization
MUST:
- Enforce authentication for all non-public resources
- Implement multi-factor authentication (MFA) for administrative access
- Use secure session management (HTTPOnly, Secure, SameSite cookies)
- Enforce strong password policies (minimum 12 characters, complexity requirements)
- Implement account lockout after failed login attempts (5 attempts)
- Log all authentication events (success and failure)
- Use the principle of least privilege for all access controls
- Verify authorization at each access point, not just at entry
MUST NOT:
- Store passwords in plaintext or reversible encryption
- Use weak hashing algorithms (MD5, SHA-1) for passwords
- Implement custom authentication schemes without security review
- Share authentication credentials between users or systems
- Grant broad access by default
Cryptography
MUST:
- Use AES-256 for symmetric encryption
- Use RSA-2048 or higher for asymmetric encryption
- Use SHA-256 or higher for hashing
- Enforce TLS 1.2 or higher for all network communications
- Store cryptographic keys securely (use key management systems, not code)
- Use cryptographically secure random number generators (not Math.random())
- Rotate encryption keys according to policy
MUST NOT:
- Hard-code encryption keys, passwords, or secrets in source code
- Use deprecated algorithms (DES, 3DES, MD5, SHA-1, SSL, TLS 1.0/1.1)
- Implement custom cryptographic algorithms
- Store secrets in version control (use secret management tools)
- Use weak or predictable initialization vectors (IVs)
Secure Error Handling
MUST:
- Implement centralized error handling
- Log all security-relevant errors with sufficient detail for investigation
- Return generic error messages to users
- Fail securely (deny access on error, don't fall back to insecure state)
- Clean up resources in finally blocks or using equivalent patterns
- Monitor and alert on unusual error patterns
MUST NOT:
- Expose stack traces to users
- Include sensitive data in error messages (passwords, keys, tokens, PII)
- Log sensitive data (passwords, credit card numbers, SSNs)
- Continue processing after critical security errors
- Suppress security exceptions without logging
Secure Configuration
MUST:
- Use environment variables or secret management for sensitive configuration
- Implement secure defaults (disable debug mode, enable security headers)
- Document all security-relevant configuration options
- Review configuration changes for security implications
- Use principle of least privilege for service accounts and API keys
- Disable unnecessary features, services, and endpoints
MUST NOT:
- Commit configuration files with secrets to version control
- Use default credentials in production
- Enable debug/verbose logging in production
- Expose administrative interfaces to public networks
- Use overly permissive CORS policies
Security Testing
MUST:
- Perform static application security testing (SAST) on every commit
- Perform dynamic application security testing (DAST) before production deployment
- Include security test cases in test suites
- Perform dependency vulnerability scanning
- Test authentication and authorization controls
- Test input validation for injection vulnerabilities
- Document security test results
MUST NOT:
- Deploy code without passing security scans
- Ignore or suppress security findings without proper justification and approval
- Test security controls in production environments
- Use production data in testing environments
Dependency Management
MUST:
- Use dependency scanning tools (e.g., Dependabot, Snyk)
- Keep dependencies up to date with security patches
- Review dependencies for known vulnerabilities before use
- Use package lock files to ensure reproducible builds
- Document approved dependencies and their versions
- Remove unused dependencies
MUST NOT:
- Use dependencies with known critical vulnerabilities
- Use abandoned or unmaintained dependencies
- Download dependencies from untrusted sources
- Bypass dependency version constraints without security review
Code Review
MUST:
- Require peer review for all code changes
- Include security review in code review process
- Use automated security scanning in PR pipelines
- Document security decisions in PR comments
- Verify security requirements are met before approval
MUST NOT:
- Merge code without required approvals
- Bypass security checks in CI/CD pipeline
- Approve your own security-critical changes
Examples
Example 1: Secure Input Validation (JavaScript)
// GOOD: Allowlist validation with type checking
function validateUsername(username) {
// Define what IS allowed
const usernameRegex = /^[a-zA-Z0-9_-]{3,20}$/;
// Validate type
if (typeof username !== 'string') {
throw new Error('Invalid input type');
}
// Validate format and length
if (!usernameRegex.test(username)) {
throw new Error('Username must be 3-20 characters and contain only letters, numbers, hyphens, and underscores');
}
return username;
}
// BAD: No validation
function validateUsernameBad(username) {
return username; // Accepts anything!
}
// BAD: Blocklist validation
function validateUsernameBad2(username) {
if (username.includes('<') || username.includes('>')) {
throw new Error('Invalid characters');
}
return username; // Still vulnerable to many attacks
}
Example 2: Secure Password Hashing (Node.js)
const bcrypt = require('bcrypt');
// GOOD: Use strong hashing with salt
async function hashPassword(password) {
// MUST use at least 12 rounds (2^12 iterations)
const saltRounds = 12;
const hashedPassword = await bcrypt.hash(password, saltRounds);
return hashedPassword;
}
async function verifyPassword(password, hashedPassword) {
return await bcrypt.compare(password, hashedPassword);
}
// BAD: Using weak hashing
const crypto = require('crypto');
function hashPasswordBad(password) {
// NEVER use MD5 or SHA-1 for passwords!
return crypto.createHash('md5').update(password).digest('hex');
}
// BAD: Storing plaintext
function storePasswordBad(password) {
return password; // NEVER store passwords in plaintext!
}
Example 3: Secure Session Management (Express.js)
const session = require('express-session');
const RedisStore = require('connect-redis')(session);
// GOOD: Secure session configuration
app.use(session({
store: new RedisStore({ client: redisClient }),
secret: process.env.SESSION_SECRET, // From environment, not hardcoded
name: 'sessionId', // Don't use default 'connect.sid'
resave: false,
saveUninitialized: false,
cookie: {
secure: true, // MUST use HTTPS
httpOnly: true, // MUST prevent JavaScript access
maxAge: 1800000, // 30 minutes
sameSite: 'strict' // CSRF protection
}
}));
// BAD: Insecure session configuration
app.use(session({
secret: 'mysecret123', // Hardcoded secret!
cookie: {
secure: false, // Allows HTTP
httpOnly: false // Vulnerable to XSS
}
}));
Example 4: Preventing SQL Injection (Node.js)
const mysql = require('mysql2/promise');
// GOOD: Parameterized queries
async function getUserByEmail(email) {
const [rows] = await connection.execute(
'SELECT * FROM users WHERE email = ?',
[email]
);
return rows[0];
}
// BAD: String concatenation
async function getUserByEmailBad(email) {
// NEVER concatenate user input into SQL!
const query = `SELECT * FROM users WHERE email = '${email}'`;
const [rows] = await connection.execute(query);
return rows[0];
}
Example 5: Secure Error Handling (Python)
import logging
# GOOD: Generic error messages to users, detailed logging
def process_payment(user_id, amount):
try:
# Process payment logic
charge_credit_card(user_id, amount)
return {"success": True, "message": "Payment processed"}
except CreditCardError as e:
# Log detailed error securely
logging.error(f"Payment failed for user {user_id}: {str(e)}",
extra={"user_id": user_id, "amount": amount})
# Return generic message to user
return {"success": False, "message": "Payment processing failed. Please try again."}
except Exception as e:
# Log unexpected errors
logging.exception(f"Unexpected error processing payment for user {user_id}")
# Return generic message
return {"success": False, "message": "An error occurred. Please contact support."}
# BAD: Exposing detailed errors
def process_payment_bad(user_id, amount):
try:
charge_credit_card(user_id, amount)
return {"success": True}
except Exception as e:
# NEVER expose stack traces or system details to users!
return {"success": False, "error": str(e), "trace": traceback.format_exc()}
Example 6: Secure Configuration (Environment Variables)
// GOOD: Use environment variables for secrets
require('dotenv').config();
const config = {
database: {
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD, // Never hardcode!
database: process.env.DB_NAME
},
api: {
key: process.env.API_KEY,
secret: process.env.API_SECRET
},
// Secure defaults
security: {
httpsOnly: true,
hstsEnabled: true,
debugMode: false
}
};
// Validate required environment variables
const required = ['DB_HOST', 'DB_USER', 'DB_PASSWORD', 'API_KEY'];
required.forEach(key => {
if (!process.env[key]) {
throw new Error(`Missing required environment variable: ${key}`);
}
});
// BAD: Hardcoded secrets
const configBad = {
database: {
host: 'localhost',
user: 'admin',
password: 'P@ssw0rd123', // NEVER hardcode passwords!
database: 'production'
},
api: {
key: 'sk_live_abcdef123456' // NEVER commit API keys!
}
};
Example 7: XSS Prevention (HTML Output Encoding)
// GOOD: Encode output before rendering
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
function displayUserComment(comment) {
const safeComment = escapeHtml(comment);
document.getElementById('comment').innerHTML = safeComment;
}
// Or use a trusted library
const DOMPurify = require('dompurify');
function displayUserContent(content) {
const clean = DOMPurify.sanitize(content);
document.getElementById('content').innerHTML = clean;
}
// BAD: Direct HTML insertion
function displayUserCommentBad(comment) {
// NEVER insert unsanitized user input into HTML!
document.getElementById('comment').innerHTML = comment;
}
Related ISMS Policies
This skill implements requirements from:
- Secure Development Policy - Primary policy for secure coding practices
- Access Control Policy - Authentication and authorization requirements
- Cryptographic Controls Policy - Encryption and hashing requirements
- Information Security Policy - Overall security framework
- Data Classification Policy - Data handling requirements
Related Documentation
- SECURITY_ARCHITECTURE.md - Security controls and architecture
- THREAT_MODEL.md - Threat analysis and mitigation
- SECURITY.md - Security vulnerability reporting
Compliance Mapping
ISO 27001:2022
- A.8.24 Use of cryptography
- A.8.25 Secure development life cycle
- A.8.26 Application security requirements
- A.8.28 Secure coding
NIST Cybersecurity Framework
- PR.DS-2: Data-in-transit is protected
- PR.DS-6: Integrity checking mechanisms verify software integrity
- PR.IP-2: A System Development Life Cycle to manage systems is implemented
CIS Controls
- Control 16: Application Software Security
- 16.1 Establish and Maintain a Secure Application Development Process
- 16.2 Establish and Maintain a Process to Accept and Address Software Vulnerabilities
- 16.10 Apply Secure Design Principles in Application Architectures
Enforcement
Violations of secure development rules:
- Critical violations (hardcoded secrets, use of banned algorithms): Block deployment, require immediate remediation
- High severity violations (missing input validation, weak authentication): Require remediation before merge
- Medium severity violations: Require remediation within sprint
- Low severity violations: Create technical debt tickets
All violations must be tracked and reported in security metrics.
Weekly Installs
16
Repository
hack23/homepageGitHub Stars
5
First Seen
Mar 1, 2026
Security Audits
Installed on
opencode16
gemini-cli16
github-copilot16
amp16
cline16
codex16