security: add slug validation, username validation, and template escaping
- Enforce SLUG_REGEX (alphanumeric + dot/dash/underscore only) in creation_error to prevent path traversal (C-1) and stored XSS (C-3). - Add File.expand_path containment check in default_path_for as defense-in-depth. - Escape slug in form action attributes (list, form views). - Validate username in change_username using the same regex as create_user (C-4). - Escape username in settings form action attributes. - Treat submitting the current username as a no-op success instead of 'taken'.
This commit is contained in:
@@ -229,6 +229,40 @@ class AdminTest < Minitest::Test
|
||||
"sweep should remove IPs with only stale entries"
|
||||
end
|
||||
|
||||
def test_create_post_rejects_invalid_slug
|
||||
login
|
||||
get "/admin/posts/new"
|
||||
post "/admin/posts",
|
||||
"_csrf" => csrf(last_response.body), "title" => "X", "slug" => "../../etc/passwd",
|
||||
"lang" => "en", "body" => "y"
|
||||
assert_includes last_response.body, "Invalid slug"
|
||||
end
|
||||
|
||||
def test_create_post_rejects_xss_in_slug
|
||||
login
|
||||
get "/admin/posts/new"
|
||||
post "/admin/posts",
|
||||
"_csrf" => csrf(last_response.body), "title" => "X", "slug" => "foo\" onclick",
|
||||
"lang" => "en", "body" => "y"
|
||||
assert_includes last_response.body, "Invalid slug"
|
||||
end
|
||||
|
||||
def test_change_username_rejects_special_chars
|
||||
login
|
||||
get "/admin/settings"
|
||||
post "/admin/settings/username",
|
||||
"_csrf" => csrf(last_response.body), "username" => "foo\" bar"
|
||||
assert_includes last_response.body, "Username may use letters"
|
||||
end
|
||||
|
||||
def test_change_username_accepts_same_name
|
||||
login
|
||||
get "/admin/settings"
|
||||
post "/admin/settings/username",
|
||||
"_csrf" => csrf(last_response.body), "username" => "admin"
|
||||
assert_includes last_response.body, "Username unchanged"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def csrf(body)
|
||||
|
||||
Reference in New Issue
Block a user