SECURITY: Fix XSS on Shared AI Conversations local Onebox (#1069)

This commit is contained in:
Rafael dos Santos Silva 2025-01-14 18:05:37 -03:00 committed by GitHub
parent cd03874b4d
commit 92f122c54d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 28 additions and 10 deletions

View File

@ -88,14 +88,7 @@ class SharedAiConversation < ActiveRecord::Base
def html_excerpt
html = +""
populated_context.each do |post|
text =
PrettyText.excerpt(
post.cooked,
400,
text_entities: true,
strip_links: true,
strip_details: true,
)
text = PrettyText.excerpt(post.cooked, 400, strip_links: true, strip_details: true)
html << "<p><b>#{post.user.username}</b>: #{text}</p>"
if html.length > 1000

View File

@ -0,0 +1,15 @@
# frozen_string_literal: true
class RebakeSharedAiConversationOneboxes < ActiveRecord::Migration[7.2]
def up
# Safe marking for rebake using raw SQL
DB.exec(<<~SQL)
UPDATE posts
SET baked_version = NULL
WHERE raw LIKE '%/discourse-ai/ai-bot/shared-ai-conversations/%';
SQL
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View File

@ -13,17 +13,20 @@ RSpec.describe SharedAiConversation, type: :model do
fab!(:user)
let(:bad_user_input) { <<~HTML }
Just trying something `<marquee style="font-size: 200px; color: red;" scrollamount=20>h4cked</marquee>`
HTML
let(:raw_with_details) { <<~HTML }
<details>
<summary>GitHub pull request diff</summary>
<p><a href="https://github.com/discourse/discourse-ai/pull/521">discourse/discourse-ai 521</a></p>
</details>
<p>This is some other text</p>
HTML
HTML
let(:bot_user) { claude_2.reload.user }
let!(:topic) { Fabricate(:private_message_topic, recipient: bot_user) }
let!(:post1) { Fabricate(:post, topic: topic, post_number: 1) }
let!(:post1) { Fabricate(:post, topic: topic, post_number: 1, raw: bad_user_input) }
let!(:post2) { Fabricate(:post, topic: topic, post_number: 2, raw: raw_with_details) }
describe ".share_conversation" do
@ -70,5 +73,12 @@ RSpec.describe SharedAiConversation, type: :model do
expect(populated_context[1].id).to eq(post2.id)
expect(populated_context[1].user.id).to eq(post2.user.id)
end
it "escapes HTML" do
conversation = described_class.share_conversation(user, topic)
onebox = conversation.onebox
expect(onebox).not_to include("</marquee>")
expect(onebox).to include("AI Conversation with Claude-2")
end
end
end