#22675 Validate RSS feed entry link schemes to prevent javascript: XSS
This commit is contained in:
parent
ebee3578b9
commit
9cf75b60c1
|
|
@ -2,7 +2,7 @@ import logging
|
|||
import uuid
|
||||
from functools import cached_property
|
||||
from hashlib import sha256
|
||||
from urllib.parse import urlencode
|
||||
from urllib.parse import urlencode, urlparse
|
||||
|
||||
import feedparser
|
||||
import requests
|
||||
|
|
@ -16,6 +16,8 @@ from django.utils.translation import gettext as _
|
|||
|
||||
from core.models import ObjectType
|
||||
from extras.choices import BookmarkOrderingChoices
|
||||
from netbox.config import get_config
|
||||
from utilities.html import clean_html
|
||||
from utilities.object_types import object_type_identifier, object_type_name
|
||||
from utilities.permissions import get_permission_for_model
|
||||
from utilities.proxy import resolve_proxies
|
||||
|
|
@ -366,8 +368,12 @@ class RSSFeedWidget(DashboardWidget):
|
|||
|
||||
# Fetch RSS content from cache if available
|
||||
if feed_content := cache.get(self.cache_key):
|
||||
feed = feedparser.FeedParserDict(feed_content)
|
||||
# Sanitize on read as well: cached content may have been written by a pre-fix
|
||||
# release (during an upgrade) and thus not yet sanitized. Idempotent.
|
||||
self.sanitize_entries(feed.get('entries', []))
|
||||
return {
|
||||
'feed': feedparser.FeedParserDict(feed_content),
|
||||
'feed': feed,
|
||||
}
|
||||
|
||||
# Fetch feed content from remote server
|
||||
|
|
@ -390,6 +396,8 @@ class RSSFeedWidget(DashboardWidget):
|
|||
# Cap number of entries
|
||||
max_entries = self.config.get('max_entries')
|
||||
feed['entries'] = feed['entries'][:max_entries]
|
||||
# Sanitize feed-controlled content before caching/rendering
|
||||
self.sanitize_entries(feed['entries'])
|
||||
# Cache the feed content
|
||||
cache.set(self.cache_key, dict(feed), self.config.get('cache_timeout'))
|
||||
|
||||
|
|
@ -397,6 +405,24 @@ class RSSFeedWidget(DashboardWidget):
|
|||
'feed': feed,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def sanitize_entries(entries):
|
||||
"""
|
||||
Sanitize feed-controlled entry content in place. The feed URL is untrusted external
|
||||
content, so we must guard against dangerous URL schemes (e.g. javascript:) in entry
|
||||
links and sanitize entry summaries as defense-in-depth.
|
||||
"""
|
||||
allowed_schemes = get_config().ALLOWED_URL_SCHEMES
|
||||
for entry in entries:
|
||||
# Blank any link whose scheme isn't permitted (blocks javascript:, data:, etc.)
|
||||
if link := entry.get('link'):
|
||||
result = urlparse(link)
|
||||
if result.scheme and result.scheme.lower() not in allowed_schemes:
|
||||
entry['link'] = ''
|
||||
# Sanitize the summary HTML
|
||||
if summary := entry.get('summary'):
|
||||
entry['summary'] = clean_html(summary, allowed_schemes)
|
||||
|
||||
|
||||
@register_widget
|
||||
class BookmarksWidget(DashboardWidget):
|
||||
|
|
|
|||
Loading…
Reference in New Issue