TRENDING
Rows of identical brass-colored apartment mailboxes with small locks and name labels along an orange corridor wall
October 9, 2026
How to Prevent Broken Object Level Authorization (IDOR) in a FastAPI App
Street-level upward view of the Monetary Authority of Singapore building and neighbouring office towers under a pale sky
October 9, 2026
Singapore’s AI Guidelines Turn Independent Review Into a Question of Who Sets the Risk Rating
Cast-iron late Qing dynasty coin minting press with a large flywheel, displayed in a museum case
October 9, 2026
Attackers Hijacked the .gh, .sl and .as Country Domains and Minted HTTPS Certificates for Google
Rows of closed oak library card catalog drawers, each with a brass pull and a blank label holder
October 9, 2026
How to Encrypt PII in Python and Keep It Searchable With Blind Indexes
Close-up of a vintage Western Electric manual telephone switchboard with orange lamps, red patch cords plugged into jacks, a rotary dial and a black handset
October 9, 2026
Microsoft’s Agent Lightning v1.0 Turns Agent Training Into a Sample-Accounting Problem
09 Oct 2026
SXZ.io SXZ.io
  • Home
Search the Site
Popular Searches:
Technology Amazon AI
Recent Posts
Two orange safety relief valves on grey pressure vessels in an industrial plant
How to Add Backpressure and Load Shedding to a Python Service Before Overload Takes It Down
October 8, 2026
Yellow diamond-shaped merging traffic warning sign showing a side road joining a main road
GitHub’s Git Rebuild Turns Repository Durability and Read Scale Into Two Separate Problems
October 8, 2026
A lugworm lying on wet sand and mud at low tide
A Compromised Admin Account Put the Shai-Hulud Worm Into AI Sandbox Maker Tensorlake’s npm SDK
October 8, 2026
SXZ.io SXZ.io
  • Home

Categories

Articles 232 Posts
News 234 Posts
Learning Hub 204 Posts
Home/Learning Hub/How to Stop CSRF Attacks in a Python Web App With Synchronizer Tokens
Learning Hub

How to Stop CSRF Attacks in a Python Web App With Synchronizer Tokens

A hands-on walkthrough of building a real CSRF vulnerability in a Python FastAPI app, proving the attack works, then fixing it with the synchronizer token pattern OWASP recommends.

August 8, 2026 14 Min Read
60

If you have ever built a login form that uses a session cookie, your app almost certainly has a Cross-Site Request Forgery (CSRF) hole waiting in it, whether you have tested for it or not. CSRF is an attack where a malicious website tricks a visitor’s browser into sending a request to a site the visitor is already logged into, using the visitor’s own cookies, without the visitor clicking anything that looks suspicious. The victim never sees a password prompt or a warning. Their browser just quietly does what the attacker wants, because the browser is designed to attach cookies to requests automatically.

Table Of Content

  • What You’ll Build and Learn
  • Prerequisites
  • What Is CSRF, Really?
  • Why Browsers Attach Cookies Automatically
  • Reading vs. Sending: Why Same-Origin Policy Doesn’t Save You
  • Step 1: Build a Vulnerable FastAPI App
  • Step 2: Prove the Attack Actually Works
  • Forging the Cross-Site POST
  • Why a Real Browser Might Have Blocked That, and Why You Still Can’t Rely on It
  • The State-Changing GET: An Even Simpler Attack
  • Step 3: Fix It With the Synchronizer Token Pattern
  • Generating and Storing the Token
  • Step 4: Prove the Fix Works
  • Step 5: Add SameSite as Defense in Depth
  • Common Mistakes and Gotchas
  • How to Verify Your Own App Is Protected
  • Next Steps

In this tutorial you will build a small, real Python web app with a classic CSRF hole in it, prove the attack actually works by forging a request yourself, then close the hole with the same defense that OWASP (the Open Web Application Security Project) recommends as the primary fix: the synchronizer token pattern. Every command in this guide was run against a real local server while writing this post, and the output shown is copied from that real session, not invented.

What You’ll Build and Learn

You will build two small FastAPI applications that share the same login and “change email” feature: one with no CSRF protection, and one protected with a per-session CSRF token. Along the way you will:

  • Watch a forged, cross-origin request successfully change a logged-in user’s email using nothing but their session cookie.
  • Learn exactly which part of default browser behavior (the SameSite cookie attribute) blocks some CSRF attacks automatically, and why you cannot rely on that alone.
  • Implement the synchronizer token pattern from scratch, using only Python’s standard library for the cryptographic parts.
  • Prove the fix works by running the same forged request again and watching it get rejected.

Prerequisites

  • Python 3.11 or newer installed (this tutorial was tested on Python 3.13.14). Check your version with python --version.
  • pip for installing packages, and comfort using a terminal.
  • curl, which ships by default on macOS, Linux, and modern Windows 10/11.
  • Basic familiarity with HTTP concepts: what a cookie is, and the difference between a GET and a POST request. You do not need prior security experience.

What Is CSRF, Really?

Before writing any code, it helps to understand the mechanism you are exploiting and then defending. HTTP itself has no memory: every request is independent. Websites fake “being logged in” using a session cookie. When you log in, the server generates a random session ID, stores it server-side against your account, and sends it to your browser in a Set-Cookie header. From then on, your browser attaches that cookie to every request it sends to that site, automatically, without asking you.

Why Browsers Attach Cookies Automatically

That automatic attachment is not a bug. It is the entire point of cookies: it is what lets you stay logged in while you click around a site without re-entering your password on every page. The problem is that the browser attaches the cookie based on the destination domain of the request, not based on which page or script triggered the request. If you are logged into travelbuddy.com in one tab, and a completely different tab has a page from evil.com that silently submits a form to travelbuddy.com, your browser will still attach your travelbuddy.com session cookie to that request. Security researchers call this ambient authority: your credentials get used just because they exist in the browser, not because you specifically authorized that particular action.

Reading vs. Sending: Why Same-Origin Policy Doesn’t Save You

A common question at this point is: doesn’t the browser’s Same-Origin Policy (SOP) stop evil.com from talking to travelbuddy.com? It stops JavaScript running on evil.com from reading the response of a cross-origin request. It does not stop the browser from sending the request in the first place. An attacker does not need to read the response to cause damage: a single unauthenticated-looking POST that changes your email address or transfers funds does its damage the moment the server processes it, whether or not the attacker’s page ever sees what came back. This read-versus-send distinction is the reason CSRF defenses are built around proving the request came from a page the server trusts, not around hiding the response.

Step 1: Build a Vulnerable FastAPI App

Let’s make this concrete. Create a project folder, set up an isolated virtual environment, and install FastAPI and an ASGI server to run it:

mkdir csrf-demo && cd csrf-demo
python -m venv venv
source venv/bin/activate   # on Windows: venv\Scripts\activate
pip install fastapi uvicorn

This tutorial was tested with fastapi==0.141.1 and uvicorn==0.52.1; any reasonably recent version of both should work the same way. Now create vulnerable_app.py:

import secrets

from fastapi import FastAPI, Request, Response
from fastapi.responses import JSONResponse

app = FastAPI()

# In-memory "database" for this demo only.
USERS = {"alice": {"password": "demo-password-123", "email": "[email protected]"}}
SESSIONS = {}  # session_id -> username


@app.post("/login")
def login(response: Response, username: str, password: str):
    user = USERS.get(username)
    if not user or user["password"] != password:
        return JSONResponse({"error": "invalid credentials"}, status_code=401)
    session_id = secrets.token_urlsafe(32)
    SESSIONS[session_id] = username
    response.set_cookie(
        key="session_id",
        value=session_id,
        httponly=True,
        samesite=None,  # deliberately omitted for this vulnerable demo
    )
    return {"message": f"logged in as {username}"}


def get_current_user(request: Request):
    session_id = request.cookies.get("session_id")
    return SESSIONS.get(session_id)


@app.post("/account/email")
def change_email(request: Request, new_email: str):
    """Vulnerable: changes email using only the session cookie, no CSRF check."""
    username = get_current_user(request)
    if not username:
        return JSONResponse({"error": "not logged in"}, status_code=401)
    USERS[username]["email"] = new_email
    return {"message": "email updated", "email": new_email}


@app.get("/account/email-get")
def change_email_via_get(request: Request, new_email: str):
    """Vulnerable AND a state-changing GET: the classic anti-pattern."""
    username = get_current_user(request)
    if not username:
        return JSONResponse({"error": "not logged in"}, status_code=401)
    USERS[username]["email"] = new_email
    return {"message": "email updated via GET", "email": new_email}

Walking through what this does: /login checks a username and password against an in-memory dictionary (standing in for a real database), generates a session ID with secrets.token_urlsafe(32), a function built specifically for generating secure, unpredictable tokens, and stores it in a SESSIONS dictionary. It then sets that session ID as a cookie on the response. Notice samesite=None: that explicitly omits the SameSite attribute from the cookie entirely, which we’re doing on purpose right now so you can see the fully unprotected case first.

/account/email is the vulnerable endpoint: it changes the logged-in user’s email address, and the only thing it checks is whether a valid session cookie is present. It never asks “did this request actually originate from my own site’s form?” That missing question is the entire vulnerability.

Start the server:

uvicorn vulnerable_app:app --host 127.0.0.1 --port 8001

Step 2: Prove the Attack Actually Works

Log in first, saving the returned cookie to a file so curl can reuse it on later requests, the same way a browser’s cookie jar would:

curl -s -i -X POST "http://127.0.0.1:8001/login?username=alice&password=demo-password-123" \
  -c cookies_alice.txt

The real response captured while writing this tutorial:

HTTP/1.1 200 OK
content-type: application/json
set-cookie: session_id=fGLDHNzdfm-kNgPvY7WqJnyxMsJ4joTlUMe3ux8R6Nk; HttpOnly; Path=/

{"message":"logged in as alice"}

Look closely at that Set-Cookie line: there is no SameSite segment at all, because we passed samesite=None in the code above. That single missing attribute is what we are about to exploit.

Forging the Cross-Site POST

On a real attack, a page on evil.com would contain a hidden auto-submitting HTML form targeting http://127.0.0.1:8001/account/email, and the victim’s browser would attach the session cookie automatically the moment that form fires, with no visible sign anything happened. We can reproduce exactly what that HTTP request looks like on the wire with curl, using alice’s stolen or ambient cookie:

curl -s -i -X POST "http://127.0.0.1:8001/account/[email protected]" \
  -b cookies_alice.txt

Real captured output:

HTTP/1.1 200 OK
content-type: application/json

{"message":"email updated","email":"[email protected]"}

Checking the account confirms it: alice’s email is now [email protected], and alice never approved that change. The request succeeded purely because it carried a valid session cookie. Nothing checked whether the request actually originated from alice’s own logged-in tab.

Why a Real Browser Might Have Blocked That, and Why You Still Can’t Rely on It

Here is an important, easy-to-miss detail. Since Chrome 80 in February 2020, Chrome has defaulted cookies with no SameSite attribute to SameSite=Lax; Firefox adopted the same default later that year, and Chromium-based Edge follows Chrome’s behavior. A Lax cookie is withheld from cross-site requests that use an unsafe method like POST, PUT, or DELETE. Safari takes a different route: instead of the same Lax-by-default rule, its Intelligent Tracking Prevention, enabled by default, treats most cookies as SameSite=Lax no matter what a site declares, and blocks many third-party cookies outright. So in most modern browsers, hitting our vulnerable /account/email endpoint from a cross-site auto-submitting POST form might actually have been silently blocked by the browser itself, even though our code never set SameSite explicitly.

Our curl reproduction still succeeded, though, and that gap matters: curl has no concept of SameSite at all. SameSite is a policy enforced by a browser’s cookie jar, not a rule enforced by the HTTP protocol or by the server. Any HTTP client that isn’t a browser (a script, another server, an older or misconfigured client) will happily send the cookie you hand it, regardless of SameSite. The same is true if your own app ever needs to set SameSite=None for a legitimate reason, such as embedding content cross-site, which disables this protection outright. This is exactly why OWASP’s CSRF Prevention Cheat Sheet describes SameSite as “useful as a defense-in-depth control” that “does not replace a proper CSRF defense in most deployments.” Relying on a browser default that you don’t control, and that doesn’t apply to non-browser clients, is not a real fix. We’ll add SameSite back in later as a second layer, but the token check has to be the real defense.

The State-Changing GET: An Even Simpler Attack

Our vulnerable app also has a second endpoint, /account/email-get, which does the same thing but through a GET request. This matters because SameSite=Lax, even as a browser default, explicitly still allows cookies on cross-site top-level navigations that use a “safe” method like GET, specifically so that clicking a normal link from an external site still keeps you logged in on the destination site. Per MDN’s own definition, that includes a user clicking a link, a script assigning document.location, or a plain HTML form submitted with method="GET".

That means an attacker doesn’t even need a hidden form. A plain link is enough:

<a href="http://127.0.0.1:8001/account/[email protected]">
  Free prize, click here!
</a>

Reproducing the click with curl:

curl -s -i -X GET "http://127.0.0.1:8001/account/[email protected]" \
  -b cookies_alice.txt
HTTP/1.1 200 OK
content-type: application/json

{"message":"email updated via GET","email":"[email protected]"}

Unlike the POST case, this attack would succeed against a real, fully up-to-date browser too, using nothing more exotic than a link the victim clicks. OWASP’s cheat sheet calls state-changing GET requests out by name, with blunt advice: “Do not use GET requests for state changing operations.” Any endpoint that changes data belongs behind POST, PUT, PATCH, or DELETE, full stop, and even then it still needs its own CSRF check, which is what we’ll build next.

Step 3: Fix It With the Synchronizer Token Pattern

The fix OWASP recommends first is the synchronizer token pattern: when a user logs in, the server generates a second secret value (the CSRF token) that is unique to that session, and stores it server-side. Every state-changing request must include that exact token, proven some way other than the cookie itself. Because a page hosted on evil.com can trigger a request but, thanks to the Same-Origin Policy, cannot read anything from travelbuddy.com, including a token embedded in a page the attacker cannot access, the attacker has no way to obtain a valid token to attach to their forged request.

Generating and Storing the Token

Create protected_app.py:

import hmac
import secrets

from fastapi import FastAPI, Header, Request, Response
from fastapi.responses import JSONResponse

app = FastAPI()

USERS = {"alice": {"password": "demo-password-123", "email": "[email protected]"}}
SESSIONS = {}      # session_id -> username
CSRF_TOKENS = {}   # session_id -> csrf_token


@app.post("/login")
def login(response: Response, username: str, password: str):
    user = USERS.get(username)
    if not user or user["password"] != password:
        return JSONResponse({"error": "invalid credentials"}, status_code=401)
    session_id = secrets.token_urlsafe(32)
    SESSIONS[session_id] = username
    CSRF_TOKENS[session_id] = secrets.token_urlsafe(32)
    response.set_cookie(
        key="session_id",
        value=session_id,
        httponly=True,
        samesite="lax",
        secure=False,  # this demo runs on plain http://localhost; use True in production
    )
    return {"message": f"logged in as {username}"}


def get_current_user(request: Request):
    session_id = request.cookies.get("session_id")
    return session_id, SESSIONS.get(session_id)


@app.get("/account/email-form")
def email_form(request: Request):
    """A logged-in page fetches its own CSRF token like this before rendering a form."""
    session_id, username = get_current_user(request)
    if not username:
        return JSONResponse({"error": "not logged in"}, status_code=401)
    return {"csrf_token": CSRF_TOKENS[session_id]}


def valid_csrf_token(session_id, submitted_token):
    real_token = CSRF_TOKENS.get(session_id)
    if not real_token or not submitted_token:
        return False
    return hmac.compare_digest(real_token, submitted_token)


@app.post("/account/email")
def change_email(
    request: Request,
    new_email: str,
    x_csrf_token: str | None = Header(default=None),
):
    """Protected: requires a valid per-session CSRF token in a custom header."""
    session_id, username = get_current_user(request)
    if not username:
        return JSONResponse({"error": "not logged in"}, status_code=401)
    if not valid_csrf_token(session_id, x_csrf_token):
        return JSONResponse({"error": "missing or invalid CSRF token"}, status_code=403)
    USERS[username]["email"] = new_email
    return {"message": "email updated", "email": new_email}

A few details worth calling out:

  • Token generation: secrets.token_urlsafe(32) uses Python’s secrets module, which is built specifically for generating cryptographically strong random values, unlike the general-purpose random module. OWASP requires CSRF tokens to be generated by “a secure method” and to be unpredictable; a 32-byte token easily clears that bar.
  • Server-side storage: the token lives in a CSRF_TOKENS dictionary keyed by session ID, mirroring how SESSIONS stores the logged-in username. In a real app both of these would live in a database or a cache like Redis, not a plain dictionary that resets when the process restarts.
  • Constant-time comparison: validation uses hmac.compare_digest() instead of Python’s == operator. A plain == comparison on strings can return slightly faster the moment it finds a mismatched character, which in principle leaks timing information an attacker could use to guess a secret one byte at a time. compare_digest() is built to take the same amount of time regardless of where a mismatch occurs, which is why it’s the standard choice for comparing secrets.
  • Where the token travels: the token is delivered via a dedicated GET /account/email-form endpoint (standing in for what would normally be a value embedded in a rendered HTML page) and submitted back via a custom X-CSRF-Token header, never as a second cookie. OWASP is explicit that the token itself should “not be transmitted in a cookie,” because anything an attacker’s forged request would carry automatically defeats the whole point.

Start this server on a different port so both can run side by side:

uvicorn protected_app:app --host 127.0.0.1 --port 8002

Step 4: Prove the Fix Works

Log in again, then immediately try the exact same forged request that worked a moment ago:

curl -s -i -X POST "http://127.0.0.1:8002/login?username=alice&password=demo-password-123" \
  -c cookies_alice2.txt

curl -s -i -X POST "http://127.0.0.1:8002/account/[email protected]" \
  -b cookies_alice2.txt

Real captured output for the forged attempt:

HTTP/1.1 403 Forbidden
content-type: application/json

{"error":"missing or invalid CSRF token"}

Blocked, and alice’s email is confirmed unchanged. Now walk through the legitimate flow the way a real page would: fetch the token first, then submit the change with that token attached.

TOKEN=$(curl -s -X GET "http://127.0.0.1:8002/account/email-form" -b cookies_alice2.txt \
  | python -c "import sys,json; print(json.load(sys.stdin)['csrf_token'])")

curl -s -i -X POST "http://127.0.0.1:8002/account/[email protected]" \
  -b cookies_alice2.txt \
  -H "X-CSRF-Token: $TOKEN"
HTTP/1.1 200 OK
content-type: application/json

{"message":"email updated","email":"[email protected]"}

That succeeded, because it carried a token the server had actually issued for that session. As one more check, try a made-up token to confirm guessing doesn’t work either:

curl -s -i -X POST "http://127.0.0.1:8002/account/[email protected]" \
  -b cookies_alice2.txt \
  -H "X-CSRF-Token: wrong-token-guess"
HTTP/1.1 403 Forbidden
content-type: application/json

{"error":"missing or invalid CSRF token"}

Three real outcomes, three different requests: no token fails, the correct token succeeds, and a wrong token fails. That’s the synchronizer token pattern working end to end.

Step 5: Add SameSite as Defense in Depth

Look back at the protected app’s login route and you’ll notice it now sets samesite="lax" explicitly, rather than leaving it unset. Starting the server and logging in again shows the difference directly in the raw header:

set-cookie: session_id=dBpBqpeUnoB-hELw2fl2pn2PZSoaMdji_ZPb7u7ONeM; HttpOnly; Path=/; SameSite=lax

This doesn’t replace the token check you just built, it backs it up. With SameSite=Lax set explicitly, a real browser will now refuse to send this cookie on a cross-site POST at all, so a forged request from evil.com gets stopped before it even reaches your server with a usable cookie attached. If your CSRF token check ever has a bug, gets accidentally skipped on a new endpoint, or a browser without SameSite support is in play, the token is still the layer doing the real work. Defense in depth means neither layer has to be perfect on its own.

If your app has a genuine reason to set SameSite=None (for example, a cookie that must be sent when your site is embedded in an iframe on another domain), treat that as a signal that your CSRF token check is no longer optional defense in depth, it’s now your only defense, so make sure every state-changing route enforces it.

Common Mistakes and Gotchas

  • Using GET for anything that changes data. As Step 2 showed, a state-changing GET route is exploitable through a plain link click, even under the modern SameSite=Lax default. Keep reads on GET and writes on POST, PUT, PATCH, or DELETE.
  • Comparing tokens with == instead of a constant-time function. Use hmac.compare_digest() in Python (or your language’s equivalent) for any secret comparison, not just CSRF tokens.
  • Storing the CSRF token only in a second cookie, with nothing binding it to the session. This is the “naive” double-submit cookie pattern, and OWASP specifically warns it’s “vulnerable to cookie injection attacks, especially when attackers control subdomains.” If you use a double-submit approach at all, sign the token (for example with HMAC using a server-side secret) so an attacker can’t simply set their own matching cookie and value.
  • Forgetting that CSRF tokens don’t stop XSS. If an attacker can run JavaScript on your own site (a separate vulnerability class called Cross-Site Scripting), they can read the page’s CSRF token directly and use it. CSRF protection and XSS protection are different problems that both need solving.
  • Assuming CORS headers protect you. CORS controls which origins are allowed to read the response of a cross-origin request from JavaScript; it does not stop the browser from sending a simple cross-origin form submission in the first place. A permissive or misconfigured CORS policy doesn’t cause CSRF, but it also does nothing to prevent it.
  • Issuing one global CSRF token for the whole app instead of one per session. If the token isn’t tied to the specific logged-in session, an attacker who obtains any valid token (say, from their own account) may be able to reuse it against a different victim.

How to Verify Your Own App Is Protected

Once you’ve wired this pattern into a real application, work through this checklist the way we did above:

  1. Log in and inspect the Set-Cookie header (in a browser, use DevTools’ Application/Storage tab; from the command line, use curl -i). Confirm HttpOnly and an explicit SameSite value are both present.
  2. Pick a state-changing route and confirm it rejects the request outright when the CSRF token header or field is missing.
  3. Confirm it also rejects a syntactically valid but wrong token, not just a missing one.
  4. Confirm the legitimate flow, fetch a token, then submit it, still succeeds.
  5. Grep your codebase for any state-changing route defined with @app.get(...) (or your framework’s equivalent) and fix or remove it.

Next Steps

The synchronizer token pattern you built here needs a server-side place to store tokens, which fits naturally into session-based apps. If you’re building a stateless API instead, look into the signed double-submit cookie pattern: the server issues an HMAC-signed token in a cookie, the client echoes that same value back in a header or form field on each request, and the server verifies the signature instead of looking anything up in a session store. From here, a few directions worth exploring next:

  • If you’re using a full framework rather than hand-rolling this, look at its built-in CSRF protection before writing your own: Django ships CsrfViewMiddleware active by default in new projects, and Flask has the well-established Flask-WTF extension. Prefer a maintained library over custom code for anything you ship to production.
  • Read through the OWASP Cross-Site Request Forgery Prevention Cheat Sheet in full; it covers additional patterns like verifying the Origin and Referer headers as extra signals.
  • If you followed our earlier tutorial on building an OAuth 2.0 Authorization Code Flow with PKCE, revisit its state parameter with fresh eyes: it exists specifically to stop CSRF attacks against the OAuth redirect step, using the same underlying idea you just implemented here.
  • Try breaking your own protected app: comment out the token check, confirm the Step 2 attack succeeds again, then put the check back and confirm it’s blocked. Deliberately breaking your own defenses is one of the fastest ways to build real confidence that they work.

Tags:

csrfFastAPIOWASPPythonWeb Security

Share

Rack of NVIDIA Tesla GPU servers connected by InfiniBand cabling in a data center
Previous Post

Red Hat’s NVIDIA DSX Integration Turns AI Factory Operations Into a Managed Platform

Natural gas power plant turbines and cooling infrastructure at the Sand Hill Energy Center in Texas
Next Post

Amazon’s New Texas Data Center Plant Could Become the Country’s Single Largest Emissions Source

No Comment! Be the first one.

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Latest
08 Oct
How to Add Backpressure and Load Shedding to a Python Service Before Overload Takes It Down
08 Oct
GitHub’s Git Rebuild Turns Repository Durability and Read Scale Into Two Separate Problems
Trending
October 8, 2026
How to Add Backpressure and Load Shedding to a Python Service Before Overload Takes It Down
October 8, 2026
GitHub’s Git Rebuild Turns Repository Durability and Read Scale Into Two Separate Problems
October 8, 2026
A Compromised Admin Account Put the Shai-Hulud Worm Into AI Sandbox Maker Tensorlake’s npm SDK
October 8, 2026
How to Prevent Broken Object Level Authorization (IDOR) in a FastAPI App
October 8, 2026
Singapore’s AI Guidelines Turn Independent Review Into a Question of Who Sets the Risk Rating
October 8, 2026
Attackers Hijacked the .gh, .sl and .as Country Domains and Minted HTTPS Certificates for Google

Related Posts

A customer-support representative wearing a headset against a dark studio background.
Articles

The Meta AI Support Hack Was a Plain Old Authorization Failure

June 7, 2026
A laptop wrapped in a chain and padlock, illustrating least-privilege controls for AI agents.
Learning Hub

How to Secure Tool-Using AI Agents Before They Touch Production

June 8, 2026
Colorful sticky notes arranged on an office wall, symbolizing governance checklists and planning.
Learning Hub

AI Governance for Agentic Apps: A Practical Checklist for Builders

June 8, 2026
A technician connects green fiber optic cables at a data center, representing a private production inference endpoint.
Learning Hub

How to Deploy a Fine-Tuned LLM Behind a Private Production Inference Endpoint

June 8, 2026
SXZ.io SXZ.io
  • [email protected]

Categories

Articles
Learning Hub
News

All Rights Reserved by SXZ.io ©2026