Secure coding practices reduce vulnerabilities at the source by ensuring that code is written safely from the first line. Secure development shifts security to the earliest stages of coding so that insecure patterns never reach production. Secure coding eliminates common attack vectors such as injection flaws, insecure authentication, authorization gaps, bad error handling, weak cryptography, and unsafe data processing.
Why Secure Coding Matters
Most vulnerabilities originate in the code itself. Insecure functions, poor validation, unsafe queries, or hardcoded secrets introduce exploitable weaknesses. Secure coding prevents these issues before they reach CI/CD, before scans detect them, and before attackers exploit them. Writing secure code reduces remediation costs and strengthens overall architecture.
Secure coding is a mindset and a discipline applied to every function, module, and logic block.
Core Secure Coding Principles
Validate All Input
Never trust user input. Validate for type, length, format, range, and constraints. Reject invalid input early before it interacts with logic, files, or queries.
Encode All Output
Output encoding prevents injection attacks by ensuring data is treated as data, not executable code.
Principle of Least Privilege
Functions, modules, and services must only have access to what they need.
Fail Safely
On error, systems must default to secure behavior (deny access, close connection, reject request).
Remove Insecure Functions
Functions such as eval, insecure deserialization, weak random generators, and outdated cryptographic methods must be avoided entirely.
Secure Error Handling
Do not reveal stack traces, query strings, internal logic, or sensitive metadata.
Secrets Must Never Be Hardcoded
API keys, tokens, passwords, encryption keys, and certificates must not appear in the code.
Secure Logging
Log events that help in security analysis but never log sensitive information such as passwords, tokens, or personal data.
Use Safe Libraries and Frameworks
Select actively maintained libraries with strong security track records.
Keep Code Simple
Complex code introduces hidden vulnerabilities. Simplicity reduces attack surface and improves maintainability.
Secure Input Validation
What to Validate
• Data format
• Allowed characters
• Data length
• Data type
• Boundary ranges
• Whitelist allowed input
Safe Validation Example (Python)
import re
if not re.fullmatch(r"[a-zA-Z0-9_]{3,20}", username):
raise ValueError("Invalid username")
Input validation must occur server-side, not just client-side.
Preventing Injection Attacks
Injection occurs when untrusted input reaches commands, queries, or interpreters.
SQL Injection Prevention
Use parameterized queries:
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
Never build SQL dynamically using string concatenation.
Command Injection Prevention
Use safe subprocess calls:
subprocess.run(["ls", "-la"])
Avoid:
os.system("ls -la " + user_input)
No eval or unsafe parsing
Avoid all dynamic code execution.
# unsafe
data = eval(user_input)
Authentication and Password Security
Password Handling Rules
• Hash passwords using modern algorithms
• Never manually implement hashing
• Use salt automatically generated
• Enforce strong password rules
Use libraries such as:
bcrypt
argon2
scrypt
Session Security
• Use secure cookies
• Enforce expiration
• Invalidate sessions on logout
• Use HTTPS only cookies
• Regenerate tokens frequently
Authorization Rules
Authorization ensures users can perform only allowed actions.
Secure Authorization Patterns
• Role-based access control
• Fine-grained permissions
• Check authorization on every request
• Never rely solely on client-side checks
• Avoid insecure direct object references
Example of secure access:
if request.user.id != resource.owner_id and not request.user.is_admin:
raise PermissionError("Unauthorized")
Safe Cryptography
Rules
• Use established libraries
• Never create custom encryption
• Use AES-256 for symmetric encryption
• Use RSA or ECC for asymmetric encryption
• Use TLS 1.2 or higher
• Randomness via secure RNG only
Safe Python example:
from secrets import token_hex
api_key = token_hex(32)
Avoid:
random.random()
Secure Error Handling
Errors must not reveal internal workings.
Unsafe
print(exception)
Safe
log.error("Operation failed")
return {"error": "Unexpected error occurred"}
Avoid leaking stack traces to users.
Logging & Monitoring
Log Security Events
• Login failures
• Permission errors
• File access attempts
• Unexpected input patterns
Do Not Log
• Passwords
• Tokens
• Credit card data
• Personal information
Secure logging example:
log.info("Failed login attempt", extra={"user": user_id})
Dependency and Supply Chain Security
Rules
• Use minimal dependencies
• Pin versions
• Scan dependencies on install
• Avoid unmaintained libraries
• Validate checksums
• Avoid libraries with poor supply chain reputation
Run scanning tools:
npm audit
pip audit
osv-scanner .
Fix dependency issues early.
Extensive Practicals
These practicals enforce secure coding at every stage.
Practical 1: Create Secure Coding Guidelines for Your Team
Add a document:
/secure-dev/secure-coding-guidelines.md
Include rules for:
• Input validation
• Output encoding
• Error handling
• Authentication
• Authorization
• Cryptography
• Logging
• Dependency hygiene
• Secrets management
This becomes the reference for all developers.
Practical 2: Validate Input in Real Code
Take any function that accepts user input.
Original unsafe code:
def search(q):
return db.query(f"SELECT * FROM items WHERE name LIKE '%{q}%'")
Rewrite into safe parameterized version:
def search(q):
q = q.strip()
cursor.execute("SELECT * FROM items WHERE name LIKE %s", (f"%{q}%",))
Test with:
'
"; DROP TABLE items; --
%_test
Ensure no injection occurs.
Practical 3: Create a Secure Authentication Flow
Implement:
-
Password hashing with argon2
-
Rate limiting login attempts
-
Password reset with signed tokens
-
HTTPS-only session cookies
Example hashing:
from argon2 import PasswordHasher
ph = PasswordHasher()
hashed = ph.hash(password)
ph.verify(hashed, login_password)
Practical 4: Fix Insecure Direct Object Reference
Original insecure endpoint:
GET /download?file=/etc/passwd
Secure version:
allowed = ["report1.pdf", "report2.pdf"]
if filename not in allowed:
raise PermissionError("Unauthorized file access")
Test with malicious payloads:
../../../app_secret.env
/etc/hosts
../
Practical 5: Replace Unsafe Cryptography
Unsafe:
encrypted = base64.b64encode(data)
Secure:
from cryptography.fernet import Fernet
key = Fernet.generate_key()
cipher = Fernet(key)
encrypted = cipher.encrypt(data)
Test encrypt/decrypt cycle.
Practical 6: Implement Secure Logging
Original:
log.info(f"User logged in with password {password}")
Secure:
log.info("User logged in", extra={"user": user_id})
Test logs to verify sensitive data never appears.
Practical 7: Add Static Code Analysis to Detect Insecure Code
Run:
bandit -r src/
Fix findings such as:
• Use of eval
• Hardcoded passwords
• Insecure temp files
• Weak hashing
• Unsafe subprocess commands
Practical 8: Add Secrets Detection to Your Repository
Run:
gitleaks detect
Test by adding a mock API key:
API_KEY = "123456789SECRET"
Verify that pipeline blocks the commit.
Practical 9: Solve Injection Vulnerabilities in a Sample Project
Take a vulnerable endpoint:
os.system("ping " + ip)
Rewrite:
subprocess.run(["ping", "-c", "4", ip])
Test with payloads:
127.0.0.1; ls
127.0.0.1 && whoami
127.0.0.1 | cat /etc/passwd
Verify they fail.
Practical 10: Implement Authorization Middleware
Write middleware:
def authorize(required_role):
def wrapper(func):
def inner(request, *args, **kwargs):
if request.user.role != required_role:
raise PermissionError("Forbidden")
return func(request, *args, **kwargs)
return inner
return wrapper
Test:
• Unauthorized user call
• Admin user call
Ensure correct behavior.
Practical 11: Fix Error Handling
Replace:
return str(e)
With:
log.error("Unexpected error", exc_info=True)
return {"error": "Request failed"}
Test by causing intentional errors.
Practical 12: Dependency Hardening
Run:
pip install safety
safety check
Fix:
• Vulnerable packages
• Outdated components
• Unsafe versions
Create file:
requirements-secure.txt
Pin secure versions.
Practical 13: Build a Local Secure Coding Testing Suite
Create:
/secure-dev/tests/
Write tests for:
• Input validation
• Authentication
• Authorization
• Error handling
• Injection prevention
• Logging correctness
Run tests for every commit.
Practical 14: Code Review Security Checklist
Add file:
/secure-dev/review-checklist.md
Checklist includes:
• Input validated?
• Output encoded?
• No secrets?
• No injection?
• Errors safe?
• Logging sanitized?
• Dependencies safe?
• Privileges minimal?
• Encryption strong?
Reviewers use this for every pull request.
Intel Dump
• Secure coding prevents vulnerabilities at the source
• Key principles include validation, encoding, least privilege, error safety, no hardcoded secrets, safe cryptography, and secure logging
• Developers must avoid insecure functions and weak logic patterns
• Dependencies require strict scanning and hygiene
• Extensive practicals include input validation, injection prevention, secure authentication, safe cryptography, logging hygiene, SAST, secrets detection, authorization middleware, error handling, and secure code review templates