Writing Secure Software: Four-Week Online Course

A four-week online course on securing web applications and AI systems, using Smarter as the case study. Smarter assumes that a model will eventually try to do something it should not, and defends with deterministic controls rather than instructions: guardrails on both the prompt and the reply, a single hardened function for every outbound request to a user-supplied URL, credentials kept in encrypted Secrets that the model never sees, and parameterized queries and tool allow lists for least privilege. Every defense is in code that students can read and test. There are twelve 30-minute recorded lectures and a 90-minute live session each week. Week 1 covers classic web security, week 2 attacks on AI applications, week 3 secrets, outbound requests and infrastructure, and week 4 secure development and disclosure. See Course Formats and Grading for the format, the grading scale and the course policies, and Writing Secure Software for the Internet for an overview of the subject.

At a Glance

Students

Developers and security students.

Deployment

A shared Smarter instance for attack and defense exercises, with an account per team. Students install Smarter from source by week 3, to read, test and scan the code.

Workload

3 hours of instruction and 4 to 6 hours of assignments each week.

Cost

Expect less than $8 USD of model charges per student, capped by a per-student Budget.

Warning

Students attack only the class’s own Smarter instance. Any real vulnerability in Smarter is reported privately, as described in the project’s SECURITY.md.

Learning Objectives

By the end of the course, students can:

  1. Find and explain common web vulnerabilities, and the defenses in a Django application.

  2. Attack and defend AI applications, including indirect prompt injection through tools and retrieved content.

  3. Explain and review how an application protects credentials and outbound requests.

  4. Threat model an application, and verify its mitigations.

  5. Use static analysis, dependency scanning and code review in a development process.

  6. Report vulnerabilities responsibly and respond to incidents.

Technical Prerequisites

  • Required: structured programming in Python or JavaScript.

  • Required: HTTP, cookies and the browser’s developer tools.

  • Required: the command line, curl, Git and a GitHub account.

  • Required: basic generative AI concepts: system and user prompts, and tool calls.

  • Required by week 3: Docker, and Smarter installed from source.

  • Helpful: Linux, DNS and IP addressing, Django, Kubernetes, and YAML.

Schedule

The files that the lectures refer to are listed in full under Smarter in the Source Code.

Week

Item

Content

1

Lecture 1

The threat landscape. Attackers, assets, attack surfaces, and the OWASP Top 10.

1

Lecture 2

Injection and cross-site scripting. SQL injection, XSS, and how Django’s ORM and templates defend against them.

1

Lecture 3

Authentication and access control. Sessions, CSRF, hashed API keys, broken object-level authorization, and account scoping in Smarter’s ownership base model.

1

Live session 1

Live exercises from PortSwigger’s Web Security Academy, then a look at Smarter’s defenses for each. Start Assignment 1.

2

Lecture 4

The OWASP Top 10 for LLM Applications. New attack surfaces: prompts, retrieved content and tools.

2

Lecture 5

Prompt injection. Direct and indirect injection, jailbreaks and exfiltration.

2

Lecture 6

Deterministic controls. Guardrails, least privilege for tools, budgets, and measuring false positives.

2

Live session 2

Review of Assignment 1. Red team exercise against prompt-only LLMClients. Start Assignment 2.

3

Lecture 7

Secrets. Encryption at rest, Secrets, credentials out of prompts and logs, and secret scanning hooks.

3

Lecture 8

SSRF and outbound requests. Metadata addresses, DNS rebinding, and smarter/smarter/apps/plugin/plugin/safe_http.py.

3

Lecture 9

Infrastructure security. Containers as non-root users with read-only application files, Calico network policies with default-deny ingress, private networks, cloud identity, and middleware that blocks scanners.

3

Live session 3

Review of Assignment 2. A guided code review of safe_http.py. Capstone proposals discussed. Start Assignment 3.

4

Lecture 10

Threat modeling. Data flow diagrams, trust boundaries, STRIDE and prioritization.

4

Lecture 11

Secure development. bandit, dependency scanning, pre-commit hooks, code review, and ADR 016.

4

Lecture 12

Disclosure and response. Security policies, CVEs, coordinated disclosure, and incident response.

4

Live session 4

Capstone presentations (about 6 minutes each, with 2 minutes of questions), and a course retrospective.

Assignments 1 to 3 are due before the next live session. Assignment 4 is due in the middle of week 4. The capstone proposal is due before Live session 3, and the capstone at the start of Live session 4.

Smarter in the Source Code

Every lecture, lab and assignment in this course rests on the files below. Every reference is to the main branch of github.com/smarter-sh/smarter, or of smarter-infrastructure where named, so that students can open each one during class. Python paths are under smarter/smarter/.

Defending an AI Application

Defense

What Smarter does

Where to look

Guardrails on input

Built-in guardrails for prompt injection by keyword and by LLM judge, semantic jailbreak detection, code injection, and redaction of personal data and secrets before the model sees them.

prompt-injection-llm-judge-input.yaml, guardrail/data/guardrails/

Guardrails on output

The model’s reply is checked too, because the model is untrusted: leaked secrets and personal data, script injection, invented citations and regulated advice.

secrets-leak-output.yaml, script-injection-output.yaml

Detectors

Deterministic detectors for credit cards (with the Luhn check), US social security numbers, email addresses, phone numbers, IP addresses, IBANs, AWS access keys, private keys, API keys, JWTs and password assignments.

guardrail/services/strategies/detectors.py

The pipeline

Guardrails run in order, at each stage, and every intervention is recorded with its rationale. Smarter Guardrail.

guardrail/services/pipeline.py, guardrail/models/guardrail.py

Least privilege for tools

A SQL Plugin runs only a fixed, parameterized query, and an MCP client offers only the tools on its allow list, such as the read-only tools of GitHub’s server.

stackademy-plugin-sql.yaml, mcpclients/github.yaml

Secrets and Outbound Requests

Defense

What Smarter does

Where to look

Secrets at rest

Encrypted with Fernet, with a key that is itself a setting held as a Pydantic SecretStr, so it is never printed.

secret/models.py, common/conf/settings.py

Credentials out of prompts

An API Plugin reaches its API through a Connection whose key is a Secret, and Smarter adds it to the request, so the model never sees it. A Proxy keeps provider keys on the server, and callers use revocable Smarter keys instead.

connection/models/api_connection.py, apps/proxy/

Server-side request forgery

One hardened function for every request to a user-supplied URL: https only, port 443, every resolved address public, no credentials in URLs, every redirect re-validated, bounded responses and timeouts. Its docstring states the remaining DNS rebinding window honestly.

plugin/plugin/safe_http.py

MCP servers

The same checks on every request to an MCP server, and no stdio transport, which would run a command on the Smarter server.

mcpclient/connection.py

Never cache a security check

The rule that validate_public_url() must resolve DNS fresh before every request, and why caching it would widen the rebinding window to the cache lifetime.

smarter-development/SKILL.md

Classic Web Security

Defense

What Smarter does

Where to look

Authentication

API keys of which only a hash is stored, compared in constant time, and refused once deactivated.

lib/drf/models.py, lib/drf/token_authentication.py

Object-level authorization

Every resource belongs to an account and a user, and querysets are filtered by owner.

account/models/metadata_with_ownership.py

Probing and scanning

Middleware that blocks requests for sensitive files and common attack paths, and throttles unauthenticated clients that generate many 404s.

lib/django/middleware/sensitive_files.py, lib/django/middleware/excessive_404.py

CSRF and CORS

Django’s CSRF protection for the console, and CORS for an embedded chat limited to the origins listed in its LLMClient’s manifest.

lib/django/middleware/csrf.py, llmclient/cors.py

Infrastructure

A non-root container with read-only application files, Calico network policies with default-deny ingress, and a private network for the cluster.

Dockerfile, smarter-infrastructure: network_policy.tf

Secure Development

Practice

What Smarter does

Where to look

Static analysis and secret scanning

bandit at medium severity and above, detect-private-key and detect-aws-credentials on every commit. ADR 016.

.pre-commit-config.yaml

Dependencies

Dependabot updates, and image scanning in Amazon ECR.

.github/dependabot.yml, build.yml

Tests that cannot touch production

The development containers hold live cloud credentials, so every cloud call in tests is faked, and tests that need real infrastructure are tagged and skipped.

smarter-infrastructure-safety/SKILL.md

Disclosure

A private address for vulnerability reports, and a policy that only the latest version is supported. Security FAQ.

SECURITY.md

Graded Assignments

Assignment 1: Web Defenses in Django

Students complete five PortSwigger labs (SQL injection, stored XSS, CSRF, an access control flaw and one of their choice), and for each, explain with code references how Smarter, as a Django application, defends against that class of attack.

Turn in: lab completion screenshots and a two-page explanation.

Criterion

Pts

Exemplary

Developing

Labs

5

All five completed.

Fewer.

Attack understanding

5

Each attack explained in the student’s own words.

Copied lab text.

Defenses in Smarter

7

Correct, with file references.

Assumed.

Clarity

3

Well organized.

Disorganized.

Assignment 2: Red Team, Blue Team

Teams submit their attack log from Live session 2, harden their own LLMClient with guardrails and least-privilege tools, are attacked again, and report the results.

Turn in: both logs, the manifests and a one-page report.

Criterion

Pts

Exemplary

Developing

Attacks

5

Varied, classified.

Repetitive.

Defenses

6

Targeted at observed attacks.

Random.

Measurement

5

Before and after, false positives tested.

None.

Honesty

4

Residual risk reported.

Claims complete protection.

Assignment 3: Secrets and SSRF Review

Students trace a provider API key from the .env file or a Secret manifest to the outbound HTTP request, listing every place it is stored, decrypted or could be logged, then assess five SSRF techniques against safe_http.py.

Turn in: a two-page review with code references.

Criterion

Pts

Exemplary

Developing

Secret lifecycle

7

Every storage and use point, with references.

Gaps.

SSRF assessment

7

Five techniques correctly assessed.

Incorrect or partial.

Recommendations

4

Specific, realistic improvements.

None.

Responsible handling

2

Weaknesses reported privately.

Published.

Assignment 4: Static Analysis and Dependencies

Students run bandit on one Smarter app and a dependency scanner (such as pip-audit or npm audit) on the project, triage the findings, and judge which matter.

Turn in: the tool output and a triage table with justifications.

Criterion

Pts

Exemplary

Developing

Complete triage

6

Every finding classified.

Some skipped.

Justification

7

Based on reading the code and the advisory.

Unjustified.

Prioritization

4

Ranked by exploitability and impact.

Unranked.

Limits

3

Notes what scanners miss.

Clean scan treated as proof.

Capstone Projects

Students choose one, propose it before Live session 3, and present it in Live session 4.

Capstone A: A Full Threat Model and Security Review

Learning objective. Carry out a professional-quality security review of a real application feature, from threat model to verified findings.

Students pick a feature of Smarter that crosses trust boundaries, such as API plugins, MCP clients or the chat API, and produce a threat model, a code review of the relevant modules, tests of the key mitigations, and a findings report.

What students turn in:

  • A threat model with a data flow diagram and STRIDE analysis.

  • A code review with references, and evidence of mitigation tests.

  • A findings report ranked by severity. Real vulnerabilities are reported privately to the maintainers and only summarized in the report.

  • A six-minute presentation.

How it is graded (100 points):

Criterion

Pts

Exemplary

Developing

Threat model

20

Complete and accurate.

Superficial.

Code review

25

Careful, with references.

Skims.

Verification

20

Mitigations tested.

Untested.

Findings

20

Ranked, reproducible, with fixes.

Vague.

Responsible handling and presentation

15

Private disclosure followed; clear presentation.

Details published.

Capstone B: A Security Feature for Smarter

Learning objective. Design, build and test a security control in a real application.

Students build a security improvement on their fork, for example a new guardrail strategy, a detector for a class of secret not yet covered, an additional check in outbound request handling, or a pre-commit hook. It needs tests that show attacks blocked and legitimate use allowed, and documentation.

What students turn in:

  • A pull request against their fork with the code, tests and documentation.

  • A two-page design note: the threat, the control, its limits, and its false positive rate.

  • A six-minute presentation.

How it is graded (100 points):

Criterion

Pts

Exemplary

Developing

Threat and design

20

Real threat; control fits it.

Unclear threat.

Implementation

20

Correct, follows the code base’s patterns.

Inconsistent.

Tests

25

Attacks blocked, legitimate use allowed, edge cases covered.

Happy path only.

Limits

15

Honest about what it does not stop.

Overclaims.

Documentation and presentation

20

Documented; clear presentation.

Undocumented.

Further Study