diff --git a/conditional/blueprints/major_project_submission.py b/conditional/blueprints/major_project_submission.py
index 5ef21cc1..f847480d 100644
--- a/conditional/blueprints/major_project_submission.py
+++ b/conditional/blueprints/major_project_submission.py
@@ -2,6 +2,9 @@
import json
import os
+import html
+import markdown
+
from flask import Blueprint
from flask import request
from flask import jsonify
@@ -52,7 +55,7 @@ def display_major_project(user_dict=None):
"tldr": p.tldr,
"time_spent": p.time_spent,
"skills": p.skills,
- "desc": p.description,
+ "desc": markdown.markdown(html.escape(p.description)),
"links": [] if p.links is None else list(filter(None, p.links.split("\n"))),
"status": p.status,
"is_owner": bool(user_dict["username"] == p.uid),
diff --git a/conditional/templates/major_project_submission.html b/conditional/templates/major_project_submission.html
index bfff3d67..0f73678c 100644
--- a/conditional/templates/major_project_submission.html
+++ b/conditional/templates/major_project_submission.html
@@ -313,7 +313,7 @@
Links
Description
-
{{p['desc']}}
+
{{p['desc'] | safe}}
diff --git a/requirements.in b/requirements.in
index c5b32e18..4fdf5cc1 100644
--- a/requirements.in
+++ b/requirements.in
@@ -30,3 +30,4 @@ structlog~=25.5.0
Werkzeug~=3.1.6
wrapt~=2.1.2
click~=8.1
+markdown~=3.10.3
diff --git a/requirements.txt b/requirements.txt
index e68b7fc0..462b002a 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -22,7 +22,7 @@ botocore==1.35.99
# -r requirements.in
# boto3
# s3transfer
-build==1.5.0
+build==1.6.1
# via pip-tools
certifi==2026.7.22
# via
@@ -30,14 +30,14 @@ certifi==2026.7.22
# sentry-sdk
cffi==2.1.1
# via cryptography
-charset-normalizer==3.4.9
+charset-normalizer==3.5.1
# via requests
click==8.4.2
# via
# -r requirements.in
# flask
# pip-tools
-cryptography==50.0.0
+cryptography==50.0.1
# via oic
csh-ldap==2.5.8
# via -r requirements.in
@@ -67,11 +67,11 @@ flask-sqlalchemy==3.1.1
# flask-migrate
future==1.0.0
# via pyjwkest
-greenlet==3.5.4
+greenlet==3.5.6
# via sqlalchemy
gunicorn==25.3.0
# via -r requirements.in
-idna==3.18
+idna==3.20
# via requests
importlib-resources==7.1.0
# via flask-pyoidc
@@ -98,6 +98,8 @@ mako==1.3.12
# -r requirements.in
# alembic
# oic
+markdown==3.10.3
+ # via -r requirements.in
markupsafe==3.0.3
# via
# -r requirements.in
@@ -123,9 +125,9 @@ pip==26.2.1
# via pip-tools
pip-tools==7.5.3
# via -r requirements.in
-platformdirs==4.11.1
+platformdirs==4.11.11
# via pylint
-psycopg2-binary==2.9.12
+psycopg2-binary==2.9.13
# via -r requirements.in
pyasn1==0.6.4
# via
@@ -139,9 +141,9 @@ pycryptodomex==3.23.0
# via
# oic
# pyjwkest
-pydantic==2.13.4
+pydantic==2.13.5
# via pydantic-settings
-pydantic-core==2.46.4
+pydantic-core==2.46.5
# via pydantic
pydantic-settings==2.15.0
# via oic
@@ -149,13 +151,13 @@ pyjwkest==1.4.4
# via oic
pylint==3.3.9
# via -r requirements.in
-pyproject-hooks==1.2.0
+pyproject-hooks==1.3.3
# via
# build
# pip-tools
python-dateutil==2.9.0.post0
# via botocore
-python-dotenv==1.2.2
+python-dotenv==1.2.3
# via pydantic-settings
python-editor==1.0.4
# via -r requirements.in
@@ -170,14 +172,14 @@ s3transfer==0.10.4
# via boto3
sentry-sdk==2.63.0
# via -r requirements.in
-setuptools==83.0.0
+setuptools==84.0.0
# via pip-tools
six==1.17.0
# via
# -r requirements.in
# pyjwkest
# python-dateutil
-sqlalchemy==2.0.51
+sqlalchemy==2.0.54
# via
# -r requirements.in
# alembic
@@ -195,11 +197,11 @@ typing-extensions==4.16.0
# pydantic-core
# sqlalchemy
# typing-inspection
-typing-inspection==0.4.2
+typing-inspection==0.4.4
# via
# pydantic
# pydantic-settings
-urllib3==2.7.0
+urllib3==2.8.0
# via
# botocore
# requests
@@ -208,7 +210,7 @@ werkzeug==3.1.8
# via
# -r requirements.in
# flask
-wheel==0.47.0
+wheel==0.48.0
# via pip-tools
wrapt==2.1.2
# via -r requirements.in