diff --git a/python/twilio/security/twiml-injection.py b/python/twilio/security/twiml-injection.py
new file mode 100644
index 0000000000..6bd9577e99
--- /dev/null
+++ b/python/twilio/security/twiml-injection.py
@@ -0,0 +1,88 @@
+from twilio.rest import Client
+import html
+from xml.sax.saxutils import escape
+
+client = Client("accountSid", "authToken")
+XML = "{}"
+
+
+def fstring(to: str, msg: str) -> None:
+ client.calls.create(
+ # ruleid: twiml-injection
+ twiml=f"{msg}",
+ to=to,
+ from_="555-555-5555",
+ )
+
+
+def format_const(to: str, msg: str) -> None:
+ twiml = XML.format(msg)
+ client.calls.create(
+ # ruleid: twiml-injection
+ twiml=twiml,
+ to=to,
+ from_="555-555-5555",
+ )
+
+
+def percent(to: str, msg: str) -> None:
+ client.calls.create(
+ # ruleid: twiml-injection
+ twiml="%s" % msg,
+ to=to,
+ from_="555-555-5555",
+ )
+
+
+def format(to: str, msg: str) -> None:
+ client.calls.create(
+ # ruleid: twiml-injection
+ twiml="{}".format(msg),
+ to=to,
+ from_="555-555-5555",
+ )
+
+
+def concat(to: str, msg: str) -> None:
+ client.calls.create(
+ # ruleid: twiml-injection
+ twiml="" + msg + "",
+ to=to,
+ from_="555-555-5555",
+ )
+
+
+def safe(to: str, msg: str) -> None:
+ client.calls.create(
+ # ok: twiml-injection
+ twiml="nsec",
+ to=to,
+ from_="555-555-5555",
+ )
+
+
+def also_safe(to: str, msg: str) -> None:
+ client.calls.create(
+ # ok: twiml-injection
+ twiml="nsec",
+ to=to,
+ from_=f"{1+2}34-323-1234",
+ )
+
+
+def html_escape(to: str, msg: str) -> None:
+ client.calls.create(
+ # ok: twiml-injection
+ twiml="" + html.escape(msg) + "",
+ to=to,
+ from_="555-555-5555",
+ )
+
+
+def xml_escape(to: str, msg: str) -> None:
+ client.calls.create(
+ # ok: twiml-injection
+ twiml="" + escape(msg) + "",
+ to=to,
+ from_="555-555-5555",
+ )
diff --git a/python/twilio/security/twiml-injection.yml b/python/twilio/security/twiml-injection.yml
new file mode 100644
index 0000000000..7f63099166
--- /dev/null
+++ b/python/twilio/security/twiml-injection.yml
@@ -0,0 +1,48 @@
+rules:
+ - id: twiml-injection
+ languages: [python]
+ severity: WARNING
+ message: >-
+ Using non-constant TwiML (Twilio Markup Language) argument when creating a
+ Twilio conversation could allow the injection of additional TwiML commands
+ metadata:
+ cwe:
+ - "CWE-91: XML Injection"
+ owasp:
+ - "A03:2021 - Injection"
+ category: security
+ technology:
+ - python
+ - twilio
+ - twiml
+ confidence: MEDIUM
+ likelihood: HIGH
+ impact: MEDIUM
+ subcategory: vuln
+ references:
+ - https://codeberg.org/fennix/funjection
+ mode: taint
+ pattern-sources:
+ - pattern: |
+ f"..."
+ - pattern: |
+ "..." % ...
+ - pattern: |
+ "...".format(...)
+
+ - patterns:
+ - pattern: $ARG
+ - pattern-inside: |
+ def $F(..., $ARG, ...):
+ ...
+
+ pattern-sanitizers:
+ - pattern: xml.sax.saxutils.escape(...)
+ - pattern: html.escape(...)
+
+ pattern-sinks:
+ - patterns:
+ - pattern: |
+ $CLIENT.calls.create(..., twiml=$SINK, ...)
+
+ - focus-metavariable: $SINK