Skip to main content

Command Palette

Search for a command to run...

Secure Coding in Python: Avoiding the Most Common Vulnerabilities

Published
6 min readView as Markdown

Python is one of the most popular programming languages in the world, loved for its simplicity, readability, and vast ecosystem of libraries. But popularity also brings attention from attackers. Whether you’re building websites, APIs, data pipelines, or automation scripts, insecure Python code can expose applications to serious risks such as data breaches, credential theft, unauthorized access, and denial-of-service attacks. Strengthening your understanding of secure coding practices is crucial—especially for learners pursuing python certification online, where security-focused training can significantly enhance real-world development skills.

Secure coding is not just an advanced skill it’s a necessity. This explores the most common Python vulnerabilities, why they occur, and how developers can avoid them using proven secure coding best practices.

1. Why Secure Coding Matters in Python

Security flaws are among the most expensive issues in software development. A simple oversight like string-based SQL queries or unsafe user input can open the door to severe vulnerabilities. For Python developers, secure coding matters because:

  • Python apps often handle sensitive user data.

  • Python powers backend systems, machine learning apps, and automation tools.

  • Python libraries and frameworks evolve quickly, and insecure configuration can lead to exploitation.

  • Attackers frequently target weak input validation, injection flaws, and insecure dependencies.

By understanding common weaknesses and applying defensive techniques, Python developers can significantly reduce the attack surface of their applications.

2. Common Python Vulnerabilities You Must Avoid

Below are the most frequent vulnerabilities observed in Python codebases, along with examples and secure alternatives.

Injection Attacks (SQL Injection, Command Injection)

Injection attacks happen when untrusted user input is used directly in queries or system commands.

Vulnerable Example

query = f"SELECT * FROM users WHERE username='{username}'"
cursor.execute(query)

An attacker can input:

' OR 1=1 --

This gives full access to user records.

Secure Approach: Use Parameterized Queries

query = "SELECT * FROM users WHERE username=%s"
cursor.execute(query, (username,))

Always use ORM frameworks like Django ORM or SQLAlchemy, which handle parameterization automatically.

Command Injection Example

Using os.system() with unvalidated input:

os.system("ping " + host)

Attackers may execute system-level commands.

Safe Alternative

import subprocess
subprocess.run(["ping", host], check=True)

Insecure Deserialization (Using pickle unsafely)

pickle can execute arbitrary code during loading. Hackers can craft malicious payloads.

Vulnerable

import pickle
data = pickle.loads(user_input)

Secure

  • Use JSON for serialization.

  • Avoid untrusted pickle files.

import json
data = json.loads(user_input)

Improper Input Validation

Many vulnerabilities originate from failing to validate user data.

Vulnerable

age = int(input("Enter age: "))

If input is non-numeric, the program crashes. Attackers use malformed input to trigger denial-of-service.

Secure

def safe_int(value):
    try:
        return int(value)
    except ValueError:
        return None

Always validate:

  • Length

  • Type

  • Format (regex)

  • Allowed character sets

Hardcoded Secrets and Credentials

Developers often push passwords, API keys, or tokens into GitHub by mistake.

Vulnerable

API_KEY = "sk_live_12345"

Secure Methods

  • Use environment variables.

  • Use secrets managers (AWS Secrets Manager, Azure Key Vault).

  • Never commit secrets in code.

import os
API_KEY = os.getenv("API_KEY")

Insecure Use of eval() and exec()

eval() can execute arbitrary Python code—one of the biggest security risks.

Vulnerable

result = eval(user_input)

Attack Example

User enters:

__import__('os').system('rm -rf /')

Alternatives

  • Use literal_eval from ast:
from ast import literal_eval
result = literal_eval(user_input)
  • Avoid dynamic execution completely whenever possible.

Weak Cryptography

Using outdated or insecure algorithms puts data at risk.

Vulnerable

import hashlib
hash = hashlib.md5(password.encode())

MD5 and SHA1 are broken.

Use Modern Cryptography

  • Use PBKDF2, bcrypt, Argon2 for passwords.

  • Use cryptography library for encryption.

from hashlib import pbkdf2_hmac
hash = pbkdf2_hmac('sha256', password.encode(), salt, 100000)

Race Conditions and Shared State Issues

Python applications, especially multithreaded ones, can be vulnerable to race conditions.

Example Problem

Two threads updating the same file simultaneously.

Secure Approach

Use:

  • Locks

  • Queues

  • Thread-safe structures

  • Atomic operations

import threading
lock = threading.Lock()

with lock:
    # secure shared operation

Improper Error Handling

Revealing internal errors can leak sensitive system details.

Vulnerable

print(e)

This exposes stack traces and internal logic.

Secure Handling

logging.error("An error occurred.")

Send safe messages to users, and detailed logs only to secure logs.

Insecure File Handling

Attackers can manipulate file paths using directory traversal.

Vulnerable

open("/user_uploads/" + filename)

Attack:

../../../etc/passwd

Safe Approach

Use safe path-joining:

import os
file_path = os.path.join("user_uploads", os.path.basename(filename))

Using Outdated Libraries

Many Python security breaches occur due to outdated packages.

Prevention

  • Run pip-audit regularly:
pip install pip-audit
pip-audit
  • Keep requirements updated.

  • Lock versions with requirements.txt.

3. Best Practices for Secure Python Coding

Now that we’ve reviewed common vulnerabilities, let’s discuss the best practices every Python developer must follow.

Validate and Sanitize All Inputs

Always assume input is malicious unless proven safe. Check:

  • Type

  • Range

  • Length

  • Allowed characters

  • Format (email, IP, URL)

Use Secure Authentication and Authorization

  • Never store plain-text passwords.

  • Implement role-based access control.

  • Use session management frameworks.

  • Rate-limit login attempts.

Protect Sensitive Data

  • Encrypt sensitive fields.

  • Mask logs.

  • Use HTTPS everywhere.

  • Protect data at rest and in transit.

Follow the Principle of Least Privilege

  • Limit access for users, processes, and application services.

  • Avoid running apps as root.

Use Virtual Environments

This avoids dependency conflicts and reduces supply-chain risk.

python -m venv venv
source venv/bin/activate

Apply Logging and Monitoring

  • Log suspicious activities.

  • Use rotating log files.

  • Avoid logging sensitive data.

Conduct Regular Security Testing

  • Static analysis tools (Bandit)

  • Dependency scanners (pip-audit, Safety)

  • Penetration testing for web apps

Install Bandit:

pip install bandit
bandit -r your_project/

4. Secure Coding Tips for Popular Python Frameworks

Python developers commonly use frameworks like Django and Flask, each with its own security considerations.

Django Security Tips

  • Keep DEBUG = False in production.

  • Use Django ORM to prevent SQL injection.

  • Always use Django’s CSRF protection.

  • Configure secure cookies (HttpOnly, Secure).

  • Rotate secret keys regularly.

Flask Security Tips

  • Use Flask extensions for authentication.

  • Enable CSRF tokens manually (Flask-WTF).

  • Sanitize templates to prevent XSS.

  • Disable autoescaping where necessary.

  • Use blueprints and environment-specific configs.

5. Real-World Examples of Python Security Failures

Example 1: Misconfigured Django App

A healthcare company exposed patient data because:

  • Debug mode was left on.

  • Sensitive keys were hardcoded.

Example 2: Unvalidated Input in a Python API

A Python-based IoT API used string concatenation for SQL queries—resulting in full database compromise.

Example 3: Credential Leakage in GitHub

Developers accidentally committed AWS API keys, leading to account takeover.

These examples highlight how basic oversights can become major security incidents.

6. A Secure Python Development Checklist

Before shipping Python code, verify:

All inputs are validated
No hardcoded secrets
All queries are parameterized
No usage of eval/exec
Latest Python version is used
Dependencies scanned
Error messages sanitized
Files handled securely

This checklist ensures that every Python component is resilient against common attacks.

Conclusion

Secure coding in Python is not optional it's an essential discipline every developer must master. As Python continues to dominate areas like web development, data science, automation, and AI, the importance of writing secure code grows. By understanding common vulnerabilities and applying best practices such as input validation, secure authentication, safe file handling, and regular security testing, developers can protect applications from dangerous exploits especially valuable for anyone taking a Python Certification Course Online to build strong, industry-ready coding skills.

Security is not a one-time activity it’s a continuous process. The more proactive you are, the safer your Python applications will be.

More from this blog

juliaana's blog

317 posts