Skip to content

Commit d83561b

Browse files
committed
Resolve DOS vulnerability in SafeFormatter
1 parent d7889b7 commit d83561b

1 file changed

Lines changed: 15 additions & 1 deletion

File tree

core/models.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import _string
12
import json
23
import logging
34
import os
@@ -10,7 +11,6 @@
1011
from string import Formatter
1112
from typing import Dict, Optional
1213

13-
import _string
1414
import discord
1515
from discord.ext import commands
1616

@@ -345,6 +345,8 @@ class _Default:
345345

346346

347347
class SafeFormatter(Formatter):
348+
max_width = 100
349+
348350
def get_field(self, field_name, args, kwargs):
349351
first, rest = _string.formatter_field_name_split(field_name)
350352

@@ -372,6 +374,18 @@ def get_field(self, field_name, args, kwargs):
372374
pass
373375
return "<Invalid>", first
374376

377+
# https://stackoverflow.com/a/79533521
378+
def format_field(self, value, format_spec):
379+
# format_spec is an expanded format spec. It cannot have any indirect
380+
# width references.
381+
for x in re.findall(r"\b\d+\b", format_spec):
382+
if int(x) > self.max_width:
383+
# This intentionally does not include the max width in the
384+
# error message, to make an attacker have to work a bit
385+
# harder.
386+
raise ValueError(f"Invalid format string width" f" specification {x} is too large")
387+
return super().format_field(value, format_spec)
388+
375389

376390
class UnseenFormatter(Formatter):
377391
def get_value(self, key, args, kwds):

0 commit comments

Comments
 (0)