Executive Summary
CVE-2026-57149 is a critical vulnerability in the Plone content management system that allows authenticated users to execute arbitrary code on vulnerable servers. The flaw exists in the plone.app.portlets package, specifically within the Classic portlet component, which improperly handles user-supplied template fields. Organizations running Plone versions prior to 5.0.8, 6.0.4, or 7.0.2 should treat this as a priority security issue requiring immediate action.
The vulnerability is particularly concerning because it requires only standard user authentication—not administrative privileges—making it accessible to a broad range of potential attackers within an organization.
What Is CVE-2026-57149?
Vulnerability Overview
CVE-2026-57149 represents a critical arbitrary code execution (ACE) vulnerability in Plone’s portlet management system. The Classic portlet, a standard component in Plone installations, fails to properly sanitize user-supplied input when processing template and macro fields. This allows attackers to inject malicious code that executes with the privileges of the Plone application process.
The root cause lies in how the Classic portlet constructs TALES (Template Attribute Language Expression Syntax) path expressions from user input. These expressions are then evaluated by the TAL path() helper without adequate validation, enabling code execution beyond simple path traversal attacks.
Affected Component: plone.app.portlets
The vulnerability is contained within the plone.app.portlets package, which provides portlet functionality for Plone CMS. Portlets are reusable content blocks that users can add to their personal dashboards or page layouts. The Classic portlet specifically allows users to define custom template content, which is where the vulnerability exists.
Key affected elements:
- Component:
plone.app.portlets.portlets.classic - Vulnerable Field: User-supplied template/macro configuration
- Execution Context: TAL path expression evaluation
- Required Permission:
plone.app.portlets.ManageOwnPortlets(default for authenticated users)
Why This Matters for Your Organization
This vulnerability poses significant business and security risks:
- Low Barrier to Entry: Requires only standard user authentication, not admin access
- Privilege Escalation: Attackers can execute code with application-level privileges
- Data Exposure: Potential access to sensitive information stored in your Plone instance
- System Compromise: Full server compromise possible depending on application privileges
- Compliance Impact: Unpatched systems may violate security compliance requirements
Organizations with multi-user Plone installations, internal portals, or content management systems face elevated risk.
Which Versions Are Vulnerable?
Plone 5.x Branch
Vulnerable versions: All releases prior to 5.0.8
The Plone 5.x series, widely deployed in production environments, is affected by this vulnerability. If you’re running any version of Plone 5 with plone.app.portlets before version 5.0.8, your installation is vulnerable.
Patched version: 5.0.8 and later
Plone 6.x Branch
Vulnerable versions: All releases prior to 6.0.4
Plone 6.x users should verify they’re running version 6.0.4 or later. This branch represents more recent deployments and may have different permission configurations than legacy installations.
Patched version: 6.0.4 and later
Plone 7.x Branch
Vulnerable versions: All releases prior to 7.0.2
The latest Plone 7.x branch is also affected. Even organizations running the newest version should verify they have the patched plone.app.portlets package.
Patched version: 7.0.2 and later
How to Check Your Version
Method 1: Using pip (Recommended)
pip show plone.app.portlets
Look for the “Version” field in the output. Compare against the patched versions listed above.
Method 2: Via Plone Control Panel
- Log in as an administrator
- Navigate to Site Setup → Add-ons
- Search for “portlets” in the installed packages list
- Note the version number displayed
Method 3: Direct File Inspection
grep -r "version" /path/to/plone/eggs/plone.app.portlets*/setup.py
Method 4: Python Command
import plone.app.portlets
print(plone.app.portlets.__version__)
Document your current version before proceeding with remediation steps.
How the Attack Works
The Classic Portlet Flaw
The Classic portlet is designed to allow users to create custom content blocks by specifying a template or macro. This flexibility is intentional—it enables non-technical users to customize their dashboard without coding. However, the implementation fails to properly validate the template path before evaluation.
When a user creates or edits a Classic portlet, they can specify:
- A template path (e.g.,
string:some/template) - A macro name
- Additional parameters
The portlet then constructs a TALES expression from these inputs and evaluates it using Plone’s TAL engine. The vulnerability occurs because user input is directly incorporated into the expression without sanitization.
TALES Path Expression Exploitation
TALES (Template Attribute Language Expression Syntax) is Plone’s expression language. It supports multiple expression types:
- path: Traverses object attributes
- string: String interpolation
- python: Python code execution
- nocall: Prevents calling objects
The vulnerability allows attackers to craft malicious TALES expressions that escape the intended “path” context and execute arbitrary Python code.
Example vulnerable input:
python: __import__('os').system('malicious command')
When this is embedded in the Classic portlet’s template field and evaluated, it executes the system command with the privileges of the Plone process.
Why Authenticated Users Are the Threat
The vulnerability requires authentication, but this is a minimal barrier:
- Default Permissions: The
plone.app.portlets.ManageOwnPortletspermission is granted to the “Member” role by default - User Registration: Most Plone sites allow self-registration
- Insider Threats: Legitimate employees or contractors with access become potential attackers
- Compromised Accounts: If any user account is compromised, the attacker gains exploitation capability
This means the threat model includes:
- Disgruntled employees
- Compromised user credentials
- Malicious contractors or partners
- Attackers who register accounts on public-facing Plone sites
Real-World Attack Scenarios
Scenario 1: Credential Harvesting
An attacker creates a Classic portlet with code that captures login credentials from other users viewing the dashboard, then exfiltrates them to an external server.
Scenario 2: Lateral Movement
An attacker uses the vulnerability to execute code that enumerates internal network resources, identifies other systems, and establishes persistence for lateral movement.
Scenario 3: Data Exfiltration
A disgruntled employee uses the vulnerability to access the Plone database, extract sensitive documents, and copy them to cloud storage.
Scenario 4: Ransomware Deployment
An attacker executes code that encrypts files on the server and connected storage, then demands ransom.
Attack Scenarios and Business Impact
Privilege Escalation Attacks
An authenticated user with basic member privileges can escalate to administrative-level access through code execution. The attacker could:
- Create a malicious Classic portlet
- Execute Python code within the portlet’s TALES expression
- Modify user roles and permissions
- Create new administrative accounts
- Disable security features or audit logging
Business Impact: Complete loss of access control; attacker gains full system administration capabilities.
Data Breach Risks
The vulnerability enables direct access to sensitive data:
- Document Access: Retrieve confidential documents stored in Plone
- Database Queries: Execute SQL queries against the Plone database
- File System Access: Read files on the server filesystem
- Credential Theft: Extract stored passwords or API keys
- PII Exposure: Access personally identifiable information of users or customers
Business Impact: Regulatory fines (GDPR, HIPAA, etc.), reputational damage, customer notification costs, legal liability.
Denial of Service Exploitation
Attackers can disrupt service availability:
- Resource Exhaustion: Execute code that consumes CPU, memory, or disk space
- Process Termination: Kill critical Plone processes
- Database Corruption: Execute commands that corrupt the database
- Network Flooding: Use the server to launch attacks against other systems
Business Impact: Service downtime, lost productivity, customer dissatisfaction, SLA violations.
Who Can Exploit This Vulnerability
Internal Threat Actors:
- Employees with Plone access
- Contractors or consultants
- Former employees with lingering access
- IT staff with elevated privileges
External Threat Actors:
- Attackers who compromise user credentials
- Attackers who register accounts on public Plone sites
- Automated scanning tools targeting known vulnerabilities
- Competitors seeking to disrupt operations
Attack Sophistication: Low to moderate. The vulnerability is straightforward to exploit once access is obtained; no advanced techniques required.
Detecting CVE-2026-57149 in Your Environment
Version Verification Steps
Step 1: Identify All Plone Instances
Document all Plone installations in your environment:
# Find Plone installations
find / -name "buildout.cfg" 2>/dev/null
find / -name "setup.py" -path "*/plone/*" 2>/dev/null
Step 2: Check Package Version
For each instance, verify the plone.app.portlets version:
cd /path/to/plone/instance
./bin/python -c "import plone.app.portlets; print(plone.app.portlets.__version__)"
Step 3: Compare Against Patched Versions
Create a spreadsheet documenting:
- Instance name/location
- Current
plone.app.portletsversion - Vulnerable status (Yes/No)
- Remediation priority
Step 4: Automated Scanning
Use vulnerability scanning tools:
# Using pip-audit
pip-audit --desc | grep -i "CVE-2026-57149"
# Using safety
safety check --json | grep -i "plone"
Log Analysis for Suspicious Activity
What to Look For:
- Portlet Management Activity
- Unusual frequency of portlet creation/modification
- Portlet changes by unexpected users
- Changes outside business hours
- Multiple failed portlet operations followed by success
- TALES Expression Patterns
- References to
python:in portlet configurations - References to
__import__ - References to
os.systemorsubprocess - Unusual string patterns in portlet templates
- Code Execution Indicators
- Unexpected system commands in logs
- Network connections from Plone process to external IPs
- File creation/modification in unexpected locations
- Process spawning from Plone application
Log Locations:
/var/log/plone/instance.log
/var/log/plone/event.log
/var/log/apache2/access.log (if using Apache)
/var/log/nginx/access.log (if using Nginx)
Sample Log Search Commands:
# Search for python: expressions in logs
grep -i "python:" /var/log/plone/*.log
# Search for suspicious imports
grep -i "__import__\|os.system\|subprocess" /var/log/plone/*.log
# Search for portlet management activity
grep -i "portlet" /var/log/plone/event.log | grep -i "modify\|create"
# Search for TALES evaluation errors
grep -i "TALES\|path()" /var/log/plone/*.log
Signs of Active Exploitation
Immediate Red Flags:
- Unexpected Code in Portlets
- Review all Classic portlets in the system
- Look for template fields containing Python code
- Check for references to system commands
- Unauthorized Administrative Changes
- New user accounts created
- Role assignments changed
- Permissions modified
- Security settings altered
- Network Anomalies
- Outbound connections from Plone server to unknown IPs
- Unusual DNS queries
- Data exfiltration patterns
- Port scanning activity
- System Resource Anomalies
- Unexpected CPU spikes
- Memory exhaustion
- Disk space consumption
- Process creation anomalies
Forensic Investigation Steps:
# List all Classic portlets and their configurations
# (Requires Plone admin access)
# Via Plone shell:
# from plone.app.portlets.portlets import classic
# [p for p in portal.objectValues() if isinstance(p, classic.Portlet)]
# Check recent file modifications
find /path/to/plone -type f -mtime -7 -ls
# Review process history
ps auxww | grep plone
# Check network connections
netstat -tulpn | grep plone
ss -tulpn | grep plone
Immediate Mitigation Actions

Priority 1: Upgrade to Patched Versions
Timeline: Complete within 24-48 hours for critical systems
Upgrading is the definitive solution and should be your primary objective.
Pre-Upgrade Checklist:
- [ ] Backup entire Plone instance (filesystem and database)
- [ ] Document current configuration
- [ ] Notify users of planned maintenance
- [ ] Schedule maintenance window
- [ ] Test upgrade in non-production environment first
- [ ] Prepare rollback plan
Upgrade Process:
# 1. Backup current state
cd /path/to/plone
tar -czf plone-backup-$(date +%Y%m%d).tar.gz .
mysqldump -u plone_user -p plone_db > plone-backup-$(date +%Y%m%d).sql
# 2. Update buildout.cfg or requirements.txt
# Change plone.app.portlets version to patched version
# For Plone 5.x: plone.app.portlets >= 5.0.8
# For Plone 6.x: plone.app.portlets >= 6.0.4
# For Plone 7.x: plone.app.portlets >= 7.0.2
# 3. Run buildout
./bin/buildout
# 4. Restart Plone
./bin/instance restart
# 5. Verify upgrade
./bin/python -c "import plone.app.portlets; print(plone.app.portlets.__version__)"
Verification Steps:
- Confirm new version is running
- Test Plone functionality
- Verify portlet management still works
- Check for any error messages in logs
Priority 2: Restrict Portlet Management Permissions
Timeline: Implement immediately if upgrade is delayed
This reduces the attack surface while you prepare for upgrade.
Steps:
- Access Plone Control Panel
- Log in as administrator
- Navigate to Site Setup → Users and Groups
- Modify Role Permissions
- Go to Site Setup → Security → Manage Permissions
- Search for “ManageOwnPortlets”
- Uncheck this permission for the “Member” role
- Keep it only for “Manager” and “Site Administrator” roles
- Document Changes
- Record which roles had permissions removed
- Note the date and time of changes
- Document business justification
Impact Assessment:
- Regular users will no longer be able to customize their dashboards
- Only administrators can manage portlets
- Functionality is reduced but security is improved
Priority 3: Unregister the Classic Portlet
Timeline: Implement if upgrade is significantly delayed
If the Classic portlet isn’t essential for your organization, unregistering it eliminates the attack vector entirely.
Method 1: Via ZCML Configuration
Edit your Plone configuration file (typically configure.zcml or portlets.xml):
<!-- Comment out or remove the Classic portlet registration -->
<!-- <interface
interface="plone.app.portlets.portlets.classic.IClassicPortlet"
type="zope.interface.interfaces.IInterface"
/> -->
Method 2: Via Python Code
# In a custom package or script
from plone.app.portlets.portlets import classic
from plone.portlets.interfaces import IPortletType
from zope.component import queryUtility
# Get the portlet type utility
portlet_type = queryUtility(IPortletType, name='plone.portlets.classic')
# Unregister it
if portlet_type:
# Remove from registry
pass
Method 3: Via Plone Interface
- Navigate to Site Setup → Manage Portlets
- Find “Classic Portlet” in the list
- If available, click to disable or unregister
Verification:
- Users should no longer see Classic portlet as an option
- Existing Classic portlets may still display but cannot be edited
- Check logs for any errors related to portlet registration
Temporary Workarounds
If you cannot upgrade or restrict permissions immediately:
- Disable Portlet Management Temporarily
- Restrict access to portlet management pages
- Use web server rules to block access to
/@@manage-portlets
- Monitor Intensively
- Increase logging verbosity
- Monitor all portlet-related activities
- Set up alerts for suspicious patterns
- Restrict User Access
- Temporarily disable user self-registration
- Audit all existing user accounts
- Remove inactive accounts
- Network Segmentation
- Isolate Plone server from sensitive systems
- Restrict outbound network access
- Monitor all network traffic
Step-by-Step Remediation Guide
Pre-Upgrade Preparation
Phase 1: Planning (Day 1)
- Assess Current State
# Document current version
./bin/python -c "import plone.app.portlets; print(plone.app.portlets.__version__)"
# Check Plone version
./bin/python -c "import Products.CMFPlone; print(Products.CMFPlone.__version__)"
# List all portlets in use
# (Via Plone admin interface or custom script)
- Create Backup Strategy
- Full filesystem backup
- Database backup
- Configuration backup
- Document backup location and verification method
- Schedule Maintenance Window
- Identify low-traffic period
- Notify all users in advance
- Plan for 1-2 hours of downtime
- Prepare communication for stakeholders
- Test Environment Setup
- Clone production environment to test server
- Verify test environment matches production
- Plan upgrade testing sequence
Phase 2: Preparation (Day 2-3)
- Execute Backups
# Full filesystem backup
tar -czf /backup/plone-full-$(date +%Y%m%d-%H%M%S).tar.gz /path/to/plone
# Database backup
mysqldump -u plone_user -p plone_db > /backup/plone-db-$(date +%Y%m%d-%H%M%S).sql
# Verify backups
tar -tzf /backup/plone-full-*.tar.gz | head -20
- Test Upgrade in Non-Production
- Restore backup to test environment
- Perform upgrade steps
- Verify functionality
- Document any issues
- Refine upgrade procedure
- Prepare Rollback Plan
- Document rollback steps
- Test rollback procedure
- Ensure backups are accessible
- Prepare communication for rollback scenario
Upgrading plone.app.portlets
Phase 3: Execution (Maintenance Window)
- Stop Plone Instance
cd /path/to/plone
./bin/instance stop
# Verify it's stopped
ps aux | grep instance
-
Update Configuration
For buildout-based installations:
# Edit buildout.cfg
[buildout]
parts = instance
[instance]
recipe = plone.recipe.zope2instance
# ... other settings ...
# Update eggs section to include patched version
eggs =
Plone
plone.app.portlets >= 5.0.8 # or 6.0.4 or 7.0.2
For pip-based installations:
# Update requirements.txt
echo "plone.app.portlets>=5.0.8" >> requirements.txt
# Or update existing line
sed -i 's/plone.app.portlets.*/plone.app.portlets>=5.0.8/' requirements.txt
- Run Buildout or Pip
# For buildout
./bin/buildout
# For pip
pip install --upgrade plone.app.portlets
- Start Plone Instance
./bin/instance start
# Monitor startup
tail -f var/log/instance.log
# Wait for "INFO Zope Ready to handle requests"
- Verify Upgrade
# Check version
./bin/python -c "import plone.app.portlets; print(plone.app.portlets.__version__)"
# Should show 5.0.8, 6.0.4, or 7.0.2 (or later)
Verifying the Patch
Phase 4: Verification
- Functional Testing
- [ ] Access Plone admin interface
- [ ] Create a test portlet
- [ ] Edit the test portlet
- [ ] Verify portlet displays correctly
- [ ] Delete the test portlet
- [ ] Check for any error messages
- Security Verification
# Verify vulnerable code is not present
grep -r "python:" /path/to/plone/eggs/plone.app.portlets*/
# Check for TALES evaluation in portlet code
grep -r "path()" /path/to/plone/eggs/plone.app.portlets*/
- Log Review
# Check for any errors or warnings
tail -100 var/log/instance.log | grep -i "error\|warning\|critical"
# Look for portlet-related messages
grep -i "portlet" var/log/instance.log | tail -20
- Performance Testing
- Monitor CPU usage
- Monitor memory usage
- Check response times
- Verify no performance degradation
Post-Upgrade Validation
Phase 5: Validation
- User Acceptance Testing
- Have key users test functionality
- Verify their workflows still work
- Collect feedback on any issues
- Security Scanning
# Run vulnerability scanner
pip-audit
safety check
# Verify CVE-2026-57149 is resolved
pip-audit --desc | grep -i "CVE-2026-57149"
- Documentation Update
- Update system documentation
- Record upgrade date and version
- Document any configuration changes
- Update runbooks and procedures
- Monitoring Enablement
- Enable enhanced logging
- Set up alerts for suspicious activity
- Configure audit trail monitoring
- Establish baseline metrics
Restricting Permissions Without Upgrading
If you cannot upgrade immediately, implement these permission restrictions to reduce risk.
Removing ManageOwnPortlets Permission
Step 1: Access Security Settings
- Log in as Plone administrator
- Navigate to Site Setup (gear icon)
- Click Security → Manage Permissions
Step 2: Locate the Permission
- Search for “ManageOwnPortlets” in the permission list
- Or scroll to find “plone.app.portlets: Manage own portlets”
Step 3: Modify Role Assignments
Current state (vulnerable):
ManageOwnPortlets:
☑ Anonymous
☑ Authenticated
☑ Member
☑ Manager
☑ Site Administrator
Desired state (restricted):
ManageOwnPortlets:
☐ Anonymous
☐ Authenticated
☐ Member
☑ Manager
☑ Site Administrator
Step 4: Save Changes
- Uncheck “Member” and “Authenticated” roles
- Click “Save”
- Verify changes are applied
Step 5: Verify Restriction
- Log out as administrator
- Log in as regular user
- Attempt to access personal dashboard
- Verify “Manage Portlets” option is not available
Role-Based Access Control Configuration
Advanced Configuration via Python
If you need more granular control, use Plone’s Python API:
# Access via Plone shell: ./bin/instance debug
from plone.api import portal
from Products.CMFCore.permissions import setDefaultRoles
site = portal.get()
# Get the permission
permission = 'plone.app.portlets.ManageOwnPortlets'
# Set default roles (only Manager and Site Administrator)
setDefaultRoles(permission, ('Manager', 'Site Administrator'))
# Verify
from Products.CMFCore.PermissionRole import PermissionRole
pr = PermissionRole(permission)
print(pr.getRoles(site))
Via ZCML Configuration
Edit your configure.zcml:
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:zcml="http://namespaces.zope.org/zcml"
i18n_domain="plone">
<!-- Restrict portlet management permission -->
<permission
id="plone.app.portlets.ManageOwnPortlets"
title="plone.app.portlets: Manage own portlets"
description="Allow users to manage their own portlets"
/>
<!-- Grant only to Manager role -->
<grant
permission="plone.app.portlets.ManageOwnPortlets"
role="Manager"
/>
</configure>
Testing Permission Changes
Test 1: Verify Regular Users Cannot Manage Portlets
# Via Plone shell
from plone.api import user, portal
site = portal.get()
test_user = user.get(username='testuser')
# Check if user has permission
from Products.CMFCore.PermissionRole import PermissionRole
permission = 'plone.app.portlets.ManageOwnPortlets'
# This should return False for regular users
has_permission = test_user.has_role('Manager', site)
print(f"User has Manager role: {has_permission}")
Test 2: Verify Administrators Can Still Manage Portlets
- Log in as administrator
- Navigate to Site Setup → Manage Portlets
- Verify you can create, edit, and delete portlets
- Verify no error messages appear
Test 3: Verify User Interface Changes
- Log in as regular user
- Navigate to personal dashboard
- Verify “Manage Portlets” button/link is not visible
- Verify existing portlets still display
Test 4: Audit Trail Review
# Check logs for permission-related messages
grep -i "permission\|unauthorized" var/log/instance.log
# Look for portlet management attempts
grep -i "portlet" var/log/instance.log | grep -i "manage"
Monitoring and Ongoing Security
Log Monitoring Best Practices
1. Configure Enhanced Logging
Edit buildout.cfg or Plone configuration:
[instance]
# ... other settings ...
# Enable debug logging
event-log-level = DEBUG
access-log-enabled = true
# Log file locations
event-log = ${buildout:directory}/var/log/instance.log
access-log = ${buildout:directory}/var/log/access.log
2. Implement Log Aggregation
Use tools like ELK Stack, Splunk, or Graylog:
# Example: Filebeat configuration for Plone logs
filebeat.inputs:
- type: log
enabled: true
paths:
- /path/to/plone/var/log/instance.log
- /path/to/plone/var/log/access.log
fields:
service: plone
environment: production
output.elasticsearch:
hosts: ["elasticsearch:9200"]
3. Set Up Alerts
Configure alerts for suspicious patterns:
# Example alert rules
alerts:
- name: "Portlet Management Activity"
condition: "portlet AND (create OR modify OR delete)"
threshold: 5 # Alert if 5+ events in 1 hour
severity: "medium"
- name: "Python Code in Portlets"
condition: "portlet AND python:"
threshold: 1 # Alert immediately
severity: "critical"
- name: "Unauthorized Access Attempts"
condition: "403 OR 401 OR unauthorized"
threshold: 10
severity: "high"
Audit Trail Review
1. Enable Audit Logging
# Via Plone shell
from plone.api import portal
from Products.CMFCore.interfaces import IContentish
site = portal.get()
# Enable audit logging for portlet changes
# (Requires plone.app.audit or similar package)
2. Regular Audit Reviews
Schedule weekly reviews:
# Generate audit report
./bin/instance debug << 'EOF'
from plone.api import portal
from DateTime import DateTime
site = portal.get()
one_week_ago = DateTime() - 7
# Query audit log
# (Implementation depends on audit package)
print("Portlet changes in past week:")
# ... audit query ...
EOF
3. Document Findings
Create audit report template:
# Weekly Audit Report - [Date]
## Portlet Management Activity
- Total portlets created: X
- Total portlets modified: Y
- Total portlets deleted: Z
- Users involved: [list]
## Suspicious Activity
- [List any suspicious patterns]
- [List any unauthorized access attempts]
- [List any policy violations]
## Recommendations
- [Action items]
- [Follow-up required]
## Sign-off
- Reviewed by: [Name]
- Date: [Date]
Continuous Vulnerability Assessment
1. Automated Scanning
# Weekly vulnerability scan
0 2 * * 0 /usr/local/bin/plone-security-scan.sh
# Script content:
#!/bin/bash
cd /path/to/plone
./bin/python -m pip-audit --desc > /var/log/plone-audit-$(date +%Y%m%d).txt
./bin/python -m safety check --json > /var/log/plone-safety-$(date +%Y%m%d).json
2. Dependency Tracking
# Generate software bill of materials (SBOM)
./bin/python -m pip freeze > /var/log/plone-dependencies-$(date +%Y%m%d).txt
# Compare against known vulnerabilities
./bin/python -m safety check --file /var/log/plone-dependencies-*.txt
3. Version Monitoring
# Monitor for security updates
# Add to cron job
0 0 * * * /usr/local/bin/check-plone-updates.sh
# Script to check for available updates
#!/bin/bash
cd /path/to/plone
./bin/python -m pip list --outdated | grep -i plone
4. Patch Management Process
Establish formal process:
“`markdown
Patch Management Policy
Critical Vulnerabilities (CVSS 9.0+)
- Apply within 24 hours
- Test in non-production first
- Document all changes
- Notify stakeholders
High Vulnerabilities (CVSS 7.0-8.9)
- Apply within