#!/usr/bin/env python3 # app.py - minimal vulnerable blog demonstrating stored XSS from flask import ( Flask, request, redirect, url_for, render_template, make_response, jsonify, abort ) import json, os app = Flask(__name__) DATA_DIR = 'data' COMMENTS_FILE = os.path.join(DATA_DIR, 'comments.json') ADMIN_TOKEN_FILE = os.path.join(DATA_DIR, 'admin_token.txt') FLAG_FILE = "flag.txt" def read_comments(): with open(COMMENTS_FILE,'r') as f: return json.load(f) def write_comments(comments): with open(COMMENTS_FILE,'w') as f: json.dump(comments, f) def read_file(path): with open(path, 'r') as f: return f.read().strip() @app.route('/') def index(): return render_template('index.html') @app.route('/post/') def post_view(post_id): comments = read_comments() return render_template('post.html', post_id=post_id, comments=comments) @app.route('/comment', methods=['POST']) def comment_post(): name = request.form.get('name','Anonymous') comment = request.form.get('comment','') comments = read_comments() next_id = max([c.get('id',0) for c in comments], default=0) + 1 comments.append({'name':name,'comment':comment,'id':next_id}) write_comments(comments) return redirect(url_for('post_view', post_id=1)) @app.route('/api/comments') def api_comments(): # returns raw comments as JSON for convenience (admin UI might use this) return jsonify(read_comments()) @app.route('/admin_login') def admin_login(): token = request.args.get('token', '') real_token = read_file(ADMIN_TOKEN_FILE) if token != real_token: abort(404) # Create response that sets a cookie named 'session' containing the flag resp = make_response(redirect(url_for('post_view', post_id=1))) flag = read_file(FLAG_FILE) resp.set_cookie('session', flag, samesite='Lax') return resp