By Speedy ·October 18, 2026· 14 min read
PCES-30-01 Study Guide: Every Objective, Mapped to Free Resources
On this page
The Python Institute's PCES™ (Certified Entry-Level Security Specialist with Python) exam is new, and the official study-resources page still says "Coming soon." This guide goes through every objective in the PCES-30-01 syllabus. For each one it gives free resources and, for every Python objective, a short lab you can run yourself.
The exam
- Code: PCES-30-01
- Items: 45 (single-select, multiple-select, and typed-answer)
- Time: 60 minutes
- Pass mark: 75% cumulative (no minimum per block)
- Assumed Python level: PCEP
- Delivery: OpenEDG TestNow, online
| Block | Items | Weight |
|---|---|---|
| 1 · Security Essentials | 10 | 22% |
| 2 · IT Systems Security | 12 | 27% |
| 3 · Python for Security Operations | 13 | 29% |
| 4 · Secure Development & Implementation in Python | 10 | 22% |
Core resources
These six sources cover almost the whole syllabus, and nearly all of them are free:
- Blocks 1–2: Professor Messer: Security+ SY0-701. The videos are free. Watch only the ones linked below (about 2 hours), not the full 15-hour course.
- Blocks 1–2: Cisco NetAcad: Introduction to Cybersecurity. Free and self-paced. Good on threats, business impact and the legal side.
- Blocks 3–4: Automate the Boring Stuff with Python. A free online book. The chapters on files, PDF/Word, Excel, CSV/JSON, scheduling and subprocess, and email match Blocks 3.2–3.5 and 4.2.3 closely.
- Block 3: Google: Automate Cybersecurity Tasks with Python. On Coursera, free to audit. Strong on log parsing and regex.
- Block 4: OWASP Cheat Sheet Series. Short, authoritative pages on input validation, XSS, SQL injection, secrets and error handling.
- Blocks 3–4: Python standard library docs:
socket,ssl,subprocess,hashlib,hmac,csv,json,html,pathlib,smtplib,sqlite3.
The Python Institute said an official PCES practice test ($29) would come out in Q3/Q4 2026. Check the Edube store before you book your exam. It is the best way to learn the question style, especially the typed-answer items.
Block 1 · Security Essentials (10 items, 22%)
1.1.1 CIA triad, authenticity, accountability (1 item)
- Messer: The CIA Triad, Non-repudiation
- Know the trade-off between security and usability, for example requiring MFA on every action. Accountability means audit logs tied to individual accounts. Authenticity means signatures and verified origin.
1.2.1 Threats vs. risks, malware, phishing, DoS/DDoS, threat actors (2 items, shared with 1.2.2)
- Messer: An Overview of Malware, plus the phishing, social engineering, Denial of Service, Threat Actors and Motivations of Threat Actors videos
- Cloudflare Learning: What is a DDoS attack?
- Worms spread on their own. Viruses need a host file and a user action. Trojans pretend to be useful software. Risk is likelihood × impact; a threat is the thing that might happen.
1.2.2 Basic protections and layered defense
- Data at rest is protected with disk or file encryption. Data in transit is protected with TLS or a VPN.
- Match each threat to its countermeasure: ransomware → offline backups, credential theft → MFA, malware → AV/EDR. Defense in depth means using several layers.
1.3.1–3 Consequences of data loss, theft and modification (3 items)
- NetAcad Intro to Cybersecurity: the module on the cost and impact of breaches. The IBM Cost of a Data Breach report has real-world figures.
- Expect scenario questions:
- Theft hits intellectual property, PII and reputation.
- Modification leads to bad decisions and safety risks, such as a wrong pharmacy dose or a falsified aviation maintenance record.
- Loss means downtime plus recovery and legal costs.
- Know the difference between intentional and accidental modification.
1.4.1 Losses from system unavailability (1 item)
- Direct losses are sales missed during the outage. Indirect losses include abandoned carts, fewer repeat customers and brand damage.
- Also know: emergency fix costs, customer compensation, delays to critical services, and regulations that require data to stay accessible.
1.5.1 GDPR, CCPA, HIPAA, breach notification, trade secrets, NDAs (1 item)
- GDPR Art. 33 (notify the authority within 72 hours) · HHS: HIPAA Breach Notification Rule · California AG: CCPA
- Scope:
- GDPR covers personal data of people in the EU.
- HIPAA covers US health data held by covered entities.
- CCPA covers California consumers.
- A trade secret is protected because it is kept secret, not because it is registered (unlike a patent).
- An accidental disclosure, such as a misdirected email, still counts as a breach.
1.6.1–2 Communication, escalation, incident response team (2 items)
- Messer: Incident Response and Incident Planning (which covers tabletop exercises and drills)
- NIST SP 800-61 Rev. 3 (April 2025). Skim the roles and responsibilities section only.
- Report early, even if you aren't sure it's an incident. Write differently for technical and non-technical readers.
- An incident record covers who, what, when, where, impact and the actions taken. Follow the escalation chain instead of skipping levels.
Block 2 · IT Systems Security (12 items, 27%)
2.1.1 Security as a continuous process (4 items, shared across 2.1.x)
Threats keep changing, so monitoring and patching never end. Typical examples are an unpatched server that gets exploited, or a policy that was never updated after a move to remote work.
2.1.2 Firewall, IDS, IPS, VPN
- Messer: Firewalls, Intrusion Prevention, Virtual Private Networks
- An IDS detects and alerts. An IPS sits inline and blocks traffic. A common question gives a scenario and asks which of the two fits.
2.1.3 Organizational safeguards
Least privilege, approved devices only, limited trust (to reduce insider threat), anonymizing data before sending it to internet services, regular security training, and keeping production separate from test.
2.1.4 Secure development practices
- OWASP Logging Cheat Sheet (what must never be logged)
- Peer code review, security requirements written at the start of a project (shift left), and masking or anonymizing PII and secrets in logs.
2.2.1 System hardening process (1 item)
- Messer: Hardening Techniques. For a real-world checklist, look at one of the CIS Benchmarks.
- Order matters: remove unneeded services, then apply updates, then configure secure settings. Harden before deployment, after any change, and on a schedule.
2.3.1–2 Ports, protocols, segmentation (2 items)
| Port | Service | Note |
|---|---|---|
| 20/21 | FTP | Plaintext. Prefer SFTP (over SSH on port 22) or FTPS |
| 22 | SSH / SFTP | Encrypted remote shell and file transfer |
| 23 | Telnet | Plaintext. Disable it |
| 25 | SMTP | Mail between servers (port 587 for client submission) |
| 53 | DNS | UDP and TCP |
| 80 / 443 | HTTP / HTTPS | 443 is HTTP over TLS |
| 3389 | RDP | Never expose it to the internet |
Every open port is attack surface. Segmentation (VLANs, a DMZ for public servers) limits how far an attacker can move inside the network.
2.4.1–3 Authentication vs. authorization, password policy, MFA (3 items)
- Messer: Authentication, Authorization, and Accounting, Multifactor Authentication · CISA: MFA
- Authentication answers "who are you?" (logging in). Authorization answers "what are you allowed to do?" (file permissions).
- MFA factors are something you know, something you have, or something you are. SMS is the weakest method and hardware tokens are the strongest.
- Exam vs. real world: the syllabus treats expiry, history and complexity as the standard password policy settings, so learn them. Current NIST SP 800-63B guidance actually discourages forced periodic expiry. If the exam asks what the policy settings are, give all three.
2.5.1–2 Cloud storage risks, shared responsibility, remote access (2 items)
- AWS Shared Responsibility Model
- The provider secures the cloud itself. The customer secures what they put in it: data, identity and access management, and bucket policies. A public S3 bucket is the classic misconfiguration.
- For remote workers: VPN, full-disk encryption, patching, screen lock, and no local admin rights.
Block 3 · Python for Security Operations (13 items, 29%, the largest block)
Only scan systems you own or have written permission to test. The exam tests this rule directly (objective 3.1.1). For practice, use
127.0.0.1, your own VMs, orscanme.nmap.org, which the Nmap project explicitly allows people to scan.
3.1.1 Authorized port scanning with socket and python-nmap (3 items, shared across 3.1.x)
python-nmap needs the nmap binary installed.
import socket
for port in (21, 22, 80, 443):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(0.5)
if s.connect_ex(("127.0.0.1", port)) == 0: # 0 means the port is open
print(port, "open")
import nmap
nm = nmap.PortScanner()
nm.scan("127.0.0.1", "20-443")
print(nm["127.0.0.1"]["tcp"].keys())
Know that connect_ex returns an error code while connect raises an exception, and know AF_INET and SOCK_STREAM.
3.1.2 Outdated versions and weak or default passwords (test environments only)
from packaging.version import Version
if Version(installed) < Version(minimum_safe):
print("outdated")
weak = {"admin", "password", "123456", "root"}
flagged = [u for u, pw in test_accounts.items() if pw in weak]
3.1.3 WHOIS and banner grabbing
Uses python-whois.
import whois
w = whois.whois("example.com"); print(w.registrar, w.expiration_date)
with socket.create_connection(("127.0.0.1", 22), timeout=3) as s:
print(s.recv(1024).decode(errors="replace")) # e.g. SSH-2.0-OpenSSH_9.6
3.2.1 TLS certificate validity and expiry (4 items, shared across 3.2.x)
import ssl, socket, datetime as dt
host = "example.com"
ctx = ssl.create_default_context() # verifies the certificate chain and hostname
with socket.create_connection((host, 443), timeout=5) as sock:
with ctx.wrap_socket(sock, server_hostname=host) as tls:
cert = tls.getpeercert()
expires = dt.datetime.fromtimestamp(ssl.cert_time_to_seconds(cert["notAfter"]), dt.timezone.utc)
days = (expires - dt.datetime.now(dt.timezone.utc)).days
if days < 30: print(f"ALERT: {host} cert expires in {days} days")
An invalid or expired certificate raises ssl.SSLCertVerificationError during the handshake.
3.2.2 Process monitoring with psutil
psutil docs: process_iter, cpu_percent, virtual_memory, net_connections.
import psutil
for p in psutil.process_iter(["pid", "name", "memory_percent"]):
if (p.info["memory_percent"] or 0) > 10:
print("high memory:", p.info)
# cpu_percent() returns 0.0 on its first call; pass interval=1 or call it twice.
3.2.3 Automated checks: firewall, pending updates, alerts, restarting services
Send alerts with smtplib and email.message.EmailMessage.
import subprocess
def active(svc):
return subprocess.run(["systemctl", "is-active", svc],
capture_output=True, text=True).stdout.strip() == "active"
if not active("ufw"):
subprocess.run(["systemctl", "restart", "ufw"], check=True)
notify_admin("ufw was down and has been restarted")
# Windows: ["netsh", "advfirewall", "show", "allprofiles", "state"]
# Pending updates (Debian/Ubuntu): ["apt", "list", "--upgradable"]
3.2.4 Running OS commands with subprocess: AV scans, log archiving
r = subprocess.run(["clamscan", "-r", "/home"], capture_output=True, text=True)
print(r.returncode) # clamscan: 0 = clean, 1 = infected file found
shutil.make_archive("/var/backups/logs-2026-10", "gztar", "/var/log/app")
Pass the command as a list, and never use shell=True with user input, because that allows command injection. Know what returncode, check=True and CalledProcessError do.
3.3.1 Correlating logs from several sources (1 item)
import re
from collections import Counter
fails = Counter()
for line in open("auth.log"):
if m := re.search(r"Failed password .* from (\d+\.\d+\.\d+\.\d+)", line):
fails[m[1]] += 1
fw_blocked = {line.split()[5] for line in open("firewall.log") if "DENY" in line}
for ip, n in fails.items():
if n >= 5 and ip in fw_blocked:
print("correlated alert:", ip, n)
3.4.1–2 Structured reports: CSV, JSON, PDF, charts, recommendations (2 items)
import csv, json, datetime as dt
rows = [{"timestamp": dt.datetime.now().isoformat(), "ip": "10.0.0.5",
"threat": "brute-force", "action": "Block IP, enforce MFA"}]
with open("report.csv", "w", newline="") as f:
w = csv.DictWriter(f, fieldnames=rows[0].keys()); w.writeheader(); w.writerows(rows)
json.dump(rows, open("report.json", "w"), indent=2)
For PDF output use fpdf2 or ReportLab, and use matplotlib for the visual summary. Every finding should include a timestamp, the IP or host, the threat type, and an actionable recommendation.
3.5.1 Scheduling with cron, Task Scheduler and APScheduler (3 items, shared across 3.5.x)
crontab.guru explains cron expressions. The APScheduler 3.x docs cover the API that most tutorials, and the exam, use.
# cron, every day at 02:00: 0 2 * * * /usr/bin/python3 /opt/sec/scan.py
# Windows: schtasks /create /tn NightlyScan /tr "python C:\sec\scan.py" /sc daily /st 02:00
from apscheduler.schedulers.blocking import BlockingScheduler
sched = BlockingScheduler()
sched.add_job(run_scan, "interval", minutes=30)
sched.add_job(run_backup, "cron", hour=2)
sched.start()
Know the five cron fields in order: minute, hour, day of month, month, day of week.
3.5.2 Backups and integrity checks
import hashlib, hmac
def sha256(path):
with open(path, "rb") as f:
return hashlib.file_digest(f, "sha256").hexdigest() # Python 3.11+
ok = hmac.compare_digest(sha256("db.sqlite"), sha256("/backup/db.sqlite"))
3.5.3 Chaining tasks
def pipeline():
findings = run_checks()
if not run_backup(): findings.append("backup failed")
cleanup_old_logs()
write_report(findings) # each step runs only after the previous one finishes
Block 4 · Secure Development in Python (10 items, 22%)
4.1.1 Static analysis with pylint and flake8 (5 items, shared across 4.1.x)
- pylint · flake8 · also useful: bandit, a linter focused on security
- pylint gives a score out of 10 and message codes in five categories (C, R, W, E, F). flake8 combines pyflakes, pycodestyle (PEP 8) and mccabe. Run
pylint file.pyandflake8 file.pyonce each so you recognize the output.
4.1.2 SQL injection and XSS
OWASP Query Parameterization · OWASP XSS Prevention
# BAD: cur.execute(f"SELECT * FROM users WHERE name = '{name}'") # input ' OR '1'='1
cur.execute("SELECT * FROM users WHERE name = ?", (name,)) # sqlite3 uses ? placeholders
import html
safe = html.escape(user_comment) # < > & " ' are converted to entities
4.1.3 Output encoding for HTML, XML and JSON
html.escape(s) # HTML
from xml.sax.saxutils import escape; escape(s) # XML: & < >
json.dumps({"msg": s}) # JSON escapes quotes, backslashes and control characters
4.1.4 Path traversal and safe error handling
OWASP: Path Traversal · OWASP Error Handling
from pathlib import Path
BASE = Path("/srv/files").resolve()
target = (BASE / requested_name).resolve() # "../../etc/passwd" resolves to a path outside BASE
if not target.is_relative_to(BASE): # Python 3.9+
raise PermissionError("invalid path")
try:
...
except Exception:
log.exception("download failed") # the full traceback goes to the server log
return "Something went wrong.", 500 # the user only sees a generic message
4.1.5 Secrets in environment variables, never in git
OWASP Secrets Management · python-dotenv
import os
api_key = os.environ["API_KEY"] # raises KeyError if it's missing
db_pw = os.getenv("DB_PASSWORD") # returns None if it's missing
# add .env to .gitignore
4.2.1 Encryption with Fernet (3 items, shared across 4.2.x)
from cryptography.fernet import Fernet
key = Fernet.generate_key() # keep the key safe; without it the data can't be decrypted
f = Fernet(key)
token = f.encrypt(b"secret") # bytes in, bytes out
f.decrypt(token) # a wrong key or altered token raises InvalidToken
open("x.enc", "wb").write(f.encrypt(open("x.txt", "rb").read()))
Fernet uses AES-128-CBC with an HMAC-SHA256 tag, so it provides both confidentiality and integrity.
4.2.2 SSH and SFTP with paramiko
import paramiko
c = paramiko.SSHClient()
c.load_system_host_keys()
c.set_missing_host_key_policy(paramiko.RejectPolicy()) # AutoAddPolicy accepts unknown hosts and allows man-in-the-middle attacks
c.connect("host", username="ops", key_filename="~/.ssh/id_ed25519")
_, out, _ = c.exec_command("uptime"); print(out.read().decode())
sftp = c.open_sftp(); sftp.put("report.pdf", "/srv/reports/report.pdf"); sftp.close()
c.close()
4.2.3 Handling PDF, DOCX and XLSX files safely
- Automate the Boring Stuff: the PDF/Word chapter and the Excel chapter
- pypdf docs. The syllabus names PyPDF2, which has been merged back into pypdf. The API is the same (
PdfReader,PdfWriter,encrypt,extract_text). - python-docx · openpyxl · oletools (its
olevbatool detects macros)
from PyPDF2 import PdfReader, PdfWriter
r = PdfReader("in.pdf"); w = PdfWriter()
for page in r.pages: w.add_page(page)
w.encrypt("long-unique-passphrase")
with open("out.pdf", "wb") as f: w.write(f)
text = r.pages[0].extract_text()
import docx
d = docx.Document("memo.docx")
d.core_properties.author = ""; d.core_properties.comments = ""; d.save("clean.docx")
import openpyxl
wb = openpyxl.load_workbook("data.xlsx")
for ws in wb.worksheets:
if ws.sheet_state != "visible": print("hidden sheet:", ws.title)
for row in ws.iter_rows():
for c in row:
if c.data_type == "f": print("formula:", c.coordinate, c.value)
Macros live in .xlsm and .docm files, not .xlsx or .docx. When you share a protected file, send its password through a different channel than the file itself.
4.3.1–2 Hashing and checksum validation (2 items)
hashlib · RFC 6151 (MD5 security considerations) · RFC 6150 (MD4 retired)
published = "9f86d081884c7d65..." # copied from the vendor's HTTPS download page
if not hmac.compare_digest(sha256("installer.exe"), published.lower()):
raise SystemExit("checksum mismatch, do not run this file")
MD4, MD5 and SHA-1 are broken because collisions can be found. Use SHA-256 or stronger (SHA-384, SHA-512, SHA3-256). A hash detects that a file changed; it does not encrypt anything.
A 3-week plan (about 1 hour a day)
| Days | Focus | Why |
|---|---|---|
| 1–4 | Block 1: Messer videos plus NetAcad's threat and impact modules | Mostly vocabulary and scenarios, so it goes quickly |
| 5–8 | Block 2: Messer videos, the ports table, AWS shared responsibility | 27% of the exam |
| 9–14 | Block 3: type out and run every lab against localhost | 29%, the largest block, and typed-answer items need real recall |
| 15–18 | Block 4: the labs plus the OWASP cheat sheets | Library APIs (Fernet, paramiko, PyPDF2) are easy points once you've used them |
| 19–21 | Take the official practice test, then review weak objectives | You need 75% overall; there is no per-block minimum |
Install everything the labs use:
pip install psutil python-nmap python-whois cryptography paramiko PyPDF2 python-docx openpyxl "apscheduler<4" fpdf2 matplotlib oletools pylint flake8 bandit
The objectives and item counts are taken from the official PCES-30-01 syllabus. Good luck on the exam.