Harden security: SSRF guard on all outbound fetches, auth fixes
- Route image-validation, Matrix image-download, and wayback/archive.today fetches through safehttp so feed-controlled URLs can't reach loopback/ RFC1918/cloud-metadata IPs (incl. via redirects). - Cap feed body size with safehttp.LimitedBody (16 MiB) to prevent OOM. - Fail closed if matrix.pickle_key is unset/<16 chars; drop the hardcoded "pete_pickle_key" default that silently weakened E2EE-at-rest. - Gate !post behind a matrix.admins allowlist; empty = disabled (channel rooms are public, so empty must not mean anyone). - Reject /\host open-redirect bypass in post-login safeNext. - Allowlist http(s) schemes for the Matrix link href; escape JSON embedded in inline <script> (prefs/sources blobs).
This commit is contained in:
@@ -3,9 +3,21 @@ package matrix
|
||||
import (
|
||||
"fmt"
|
||||
"html"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// safeHref returns raw if it is an http(s) URL, else "". Keeps feed-supplied
|
||||
// links from injecting javascript:/data: schemes into the formatted_body href
|
||||
// (html.EscapeString blocks attribute breakout but not the scheme itself).
|
||||
func safeHref(raw string) string {
|
||||
u, err := url.Parse(strings.TrimSpace(raw))
|
||||
if err != nil || (u.Scheme != "http" && u.Scheme != "https") {
|
||||
return ""
|
||||
}
|
||||
return raw
|
||||
}
|
||||
|
||||
// PostableStory contains the data needed to format and send a story.
|
||||
type PostableStory struct {
|
||||
ImageURL string
|
||||
@@ -30,11 +42,16 @@ func formatPost(s *PostableStory) (plain, htmlBody string) {
|
||||
|
||||
// HTML body
|
||||
var htmlParts []string
|
||||
htmlParts = append(htmlParts, fmt.Sprintf(
|
||||
`<strong><a href="%s">%s</a></strong>`,
|
||||
html.EscapeString(s.ArticleURL),
|
||||
html.EscapeString(s.Headline),
|
||||
))
|
||||
if href := safeHref(s.ArticleURL); href != "" {
|
||||
htmlParts = append(htmlParts, fmt.Sprintf(
|
||||
`<strong><a href="%s">%s</a></strong>`,
|
||||
html.EscapeString(href),
|
||||
html.EscapeString(s.Headline),
|
||||
))
|
||||
} else {
|
||||
// Non-http(s) link: render the headline without an anchor.
|
||||
htmlParts = append(htmlParts, fmt.Sprintf(`<strong>%s</strong>`, html.EscapeString(s.Headline)))
|
||||
}
|
||||
if s.Lede != "" {
|
||||
htmlParts = append(htmlParts, html.EscapeString(s.Lede))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user