or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

dom.mdelementtree.mdexceptions.mdindex.mdsax.mdstdlib-patching.mdxmlrpc.md

stdlib-patching.mddocs/

0

# System-wide Protection

1

2

Experimental system-wide XML protection by monkey-patching all standard library XML modules with defused alternatives. This provides comprehensive protection across an entire Python application without requiring individual module imports to be changed.

3

4

## Capabilities

5

6

### Global Monkey Patching

7

8

System-wide monkey patching function that replaces all standard library XML modules with defused alternatives.

9

10

```python { .api }

11

def defuse_stdlib():

12

"""

13

Monkey patch and defuse all standard library XML packages.

14

15

Replaces the following standard library modules with defused alternatives:

16

- xml.etree.ElementTree -> defusedxml.ElementTree

17

- xml.etree.cElementTree -> defusedxml.cElementTree

18

- xml.sax -> defusedxml.sax

19

- xml.dom.minidom -> defusedxml.minidom

20

- xml.dom.pulldom -> defusedxml.pulldom

21

- xml.dom.expatbuilder -> defusedxml.expatbuilder

22

- xml.sax.expatreader -> defusedxml.expatreader

23

- xmlrpc.client/xmlrpclib -> defusedxml.xmlrpc (via monkey_patch)

24

25

Returns:

26

dict: Mapping of defused modules to original stdlib modules

27

28

Warning:

29

This is an EXPERIMENTAL feature. The monkey patch is global

30

and affects all XML processing in the current Python process.

31

Use with caution in production environments.

32

"""

33

```

34

35

**Usage Examples:**

36

37

```python

38

import defusedxml

39

40

# Apply global XML security patches

41

defused_modules = defusedxml.defuse_stdlib()

42

print(f"Defused {len(defused_modules)} XML modules")

43

44

# Now all XML processing uses defused implementations automatically

45

import xml.etree.ElementTree as ET # Actually uses defusedxml.ElementTree

46

import xml.sax as sax # Actually uses defusedxml.sax

47

import xml.dom.minidom as minidom # Actually uses defusedxml.minidom

48

49

# Parse XML normally - it's automatically secured

50

root = ET.fromstring('<root><item>value</item></root>')

51

print(f"Root element: {root.tag}")

52

53

# SAX parsing is also automatically secured

54

from xml.sax.handler import ContentHandler

55

56

class MyHandler(ContentHandler):

57

def startElement(self, name, attrs):

58

print(f"Element: {name}")

59

60

handler = MyHandler()

61

sax.parseString('<root><item>test</item></root>', handler)

62

```

63

64

## Implementation Details

65

66

The `defuse_stdlib()` function works by:

67

68

1. **Module Import**: Importing all defusedxml modules to ensure they're available

69

2. **Standard Library Import**: Importing corresponding standard library modules

70

3. **Attribute Replacement**: Replacing public attributes in standard library modules with defused equivalents

71

4. **XML-RPC Patching**: Applying special XML-RPC monkey patches via `xmlrpc.monkey_patch()`

72

5. **Return Mapping**: Returning a dictionary mapping defused modules to original modules

73

74

## Security Considerations

75

76

### Advantages

77

78

- **Comprehensive Protection**: All XML processing in the application is automatically secured

79

- **Zero Code Changes**: Existing code continues to work without modification

80

- **Consistent Security**: No risk of accidentally using unsecured XML processing

81

- **Third-party Library Protection**: Libraries that use standard XML modules are automatically protected

82

83

### Disadvantages and Risks

84

85

- **Global Side Effects**: Affects all XML processing system-wide, potentially breaking compatibility

86

- **Experimental Status**: Not recommended for production use without thorough testing

87

- **Performance Impact**: May introduce slight performance overhead

88

- **Debugging Complexity**: Stack traces may be confusing due to module replacement

89

- **Library Compatibility**: Some libraries may break if they rely on specific standard library behavior

90

91

## Common Usage Patterns

92

93

### Application Initialization

94

95

```python

96

import defusedxml

97

import logging

98

99

def initialize_security():

100

"""Initialize application-wide XML security."""

101

try:

102

defused_modules = defusedxml.defuse_stdlib()

103

logging.info(f"XML security initialized: defused {len(defused_modules)} modules")

104

105

# Log which modules were defused

106

for defused_mod, stdlib_mod in defused_modules.items():

107

if stdlib_mod:

108

logging.debug(f"Defused: {defused_mod.__name__} -> {stdlib_mod.__name__}")

109

else:

110

logging.debug(f"Patched: {defused_mod.__name__}")

111

112

return True

113

except Exception as e:

114

logging.error(f"Failed to initialize XML security: {e}")

115

return False

116

117

# Call during application startup

118

if __name__ == "__main__":

119

if initialize_security():

120

print("Application starting with XML security enabled")

121

main()

122

else:

123

print("Warning: XML security initialization failed")

124

main()

125

```

126

127

### Conditional Security Application

128

129

```python

130

import os

131

import defusedxml

132

133

def apply_xml_security():

134

"""Apply XML security based on configuration."""

135

136

# Check environment variable

137

enable_security = os.getenv('ENABLE_XML_SECURITY', 'true').lower() == 'true'

138

139

if enable_security:

140

print("Applying system-wide XML security patches...")

141

defused_modules = defusedxml.defuse_stdlib()

142

print(f"Successfully defused {len(defused_modules)} XML modules")

143

else:

144

print("XML security patches disabled by configuration")

145

146

# Apply security conditionally

147

apply_xml_security()

148

149

# Rest of application continues normally

150

import xml.etree.ElementTree as ET

151

# This uses defused implementation if security was applied

152

```

153

154

### Testing with Security Patches

155

156

```python

157

import unittest

158

import defusedxml

159

160

class TestWithXMLSecurity(unittest.TestCase):

161

"""Test case that applies XML security patches."""

162

163

@classmethod

164

def setUpClass(cls):

165

"""Apply XML security patches before running tests."""

166

cls.defused_modules = defusedxml.defuse_stdlib()

167

print(f"Test suite using defused XML modules: {len(cls.defused_modules)}")

168

169

def test_xml_parsing(self):

170

"""Test that XML parsing works with security patches."""

171

import xml.etree.ElementTree as ET

172

173

# This should work normally

174

xml_content = '<root><item>test</item></root>'

175

root = ET.fromstring(xml_content)

176

self.assertEqual(root.tag, 'root')

177

self.assertEqual(root[0].text, 'test')

178

179

def test_malicious_xml_blocked(self):

180

"""Test that malicious XML is blocked."""

181

import xml.etree.ElementTree as ET

182

import defusedxml

183

184

# XML with external entity (should be blocked)

185

malicious_xml = '''<?xml version="1.0"?>

186

<!DOCTYPE root [

187

<!ENTITY external SYSTEM "file:///etc/passwd">

188

]>

189

<root>&external;</root>'''

190

191

with self.assertRaises(defusedxml.ExternalReferenceForbidden):

192

ET.fromstring(malicious_xml)

193

194

if __name__ == '__main__':

195

unittest.main()

196

```

197

198

### Library Integration

199

200

```python

201

import defusedxml

202

203

class SecureXMLProcessor:

204

"""XML processor that ensures security is applied."""

205

206

def __init__(self, auto_defuse=True):

207

"""Initialize processor with optional auto-defusing."""

208

self.auto_defuse = auto_defuse

209

self.defused_modules = None

210

211

if auto_defuse:

212

self.enable_security()

213

214

def enable_security(self):

215

"""Enable XML security patches."""

216

if not self.defused_modules:

217

self.defused_modules = defusedxml.defuse_stdlib()

218

print(f"XML security enabled: {len(self.defused_modules)} modules defused")

219

220

def process_xml(self, xml_content):

221

"""Process XML content with security enabled."""

222

import xml.etree.ElementTree as ET

223

224

try:

225

root = ET.fromstring(xml_content)

226

return self._extract_data(root)

227

except Exception as e:

228

print(f"XML processing failed: {e}")

229

return None

230

231

def _extract_data(self, root):

232

"""Extract data from XML root element."""

233

data = {'tag': root.tag, 'attributes': dict(root.attrib)}

234

235

# Extract child elements

236

children = []

237

for child in root:

238

children.append({

239

'tag': child.tag,

240

'text': child.text,

241

'attributes': dict(child.attrib)

242

})

243

244

data['children'] = children

245

return data

246

247

# Usage

248

processor = SecureXMLProcessor()

249

result = processor.process_xml('<root><item id="1">value</item></root>')

250

print(result)

251

```

252

253

### Monitoring and Logging

254

255

```python

256

import defusedxml

257

import logging

258

import sys

259

260

class XMLSecurityMonitor:

261

"""Monitor XML security status and violations."""

262

263

def __init__(self):

264

self.security_enabled = False

265

self.defused_modules = None

266

self.violation_count = 0

267

268

# Set up logging

269

logging.basicConfig(level=logging.INFO)

270

self.logger = logging.getLogger(__name__)

271

272

def enable_security(self):

273

"""Enable XML security with monitoring."""

274

try:

275

self.defused_modules = defusedxml.defuse_stdlib()

276

self.security_enabled = True

277

278

self.logger.info(f"XML security enabled: {len(self.defused_modules)} modules defused")

279

280

# Install exception handler to monitor violations

281

self._install_violation_handler()

282

283

except Exception as e:

284

self.logger.error(f"Failed to enable XML security: {e}")

285

self.security_enabled = False

286

287

def _install_violation_handler(self):

288

"""Install handler to monitor security violations."""

289

original_excepthook = sys.excepthook

290

monitor = self

291

292

def security_aware_excepthook(exctype, value, traceback):

293

if issubclass(exctype, defusedxml.DefusedXmlException):

294

monitor.violation_count += 1

295

monitor.logger.warning(f"XML security violation #{monitor.violation_count}: {value}")

296

297

original_excepthook(exctype, value, traceback)

298

299

sys.excepthook = security_aware_excepthook

300

301

def get_status(self):

302

"""Get current security status."""

303

return {

304

'security_enabled': self.security_enabled,

305

'defused_modules': len(self.defused_modules) if self.defused_modules else 0,

306

'violation_count': self.violation_count

307

}

308

309

# Usage

310

monitor = XMLSecurityMonitor()

311

monitor.enable_security()

312

313

# Later in application

314

status = monitor.get_status()

315

print(f"XML Security Status: {status}")

316

```

317

318

## Best Practices

319

320

### Production Considerations

321

322

1. **Thorough Testing**: Test all XML processing functionality after applying patches

323

2. **Staged Rollout**: Apply in development/staging environments first

324

3. **Monitoring**: Implement monitoring for XML security violations

325

4. **Fallback Plan**: Have a plan to disable patches if compatibility issues arise

326

5. **Documentation**: Document the use of system-wide patches for maintenance teams

327

328

### Alternative Approaches

329

330

Instead of system-wide patching, consider:

331

332

```python

333

# Selective module replacement

334

import defusedxml.ElementTree as ET # Explicitly use defused version

335

import defusedxml.sax as sax # Explicitly use defused version

336

337

# Library-specific protection

338

import defusedxml.xmlrpc as xmlrpc_defused

339

xmlrpc_defused.monkey_patch() # Only patch XML-RPC

340

341

# Application-level wrappers

342

def safe_parse_xml(xml_content):

343

import defusedxml.ElementTree as ET

344

return ET.fromstring(xml_content)

345

```

346

347

## Migration Considerations

348

349

When migrating from individual defused imports to system-wide patching:

350

351

```python

352

# Before: Individual imports

353

import defusedxml.ElementTree as ET

354

import defusedxml.sax as sax

355

root = ET.fromstring(xml_content)

356

357

# After: System-wide patching

358

import defusedxml

359

defusedxml.defuse_stdlib()

360

361

import xml.etree.ElementTree as ET # Now automatically defused

362

import xml.sax as sax # Now automatically defused

363

root = ET.fromstring(xml_content) # Same API, but secured

364

```

365

366

The main advantage is that existing code and third-party libraries automatically benefit from security protections without modification.