Skip to content

Commit 0e04a8b

Browse files
authored
fix: explicitly escape sentry-trace and baggage (#1091)
1 parent ecae7a3 commit 0e04a8b

2 files changed

Lines changed: 98 additions & 2 deletions

File tree

src/Sentry/Laravel/Integration.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ public static function sentryMeta(): string
193193
*/
194194
public static function sentryTracingMeta(): string
195195
{
196-
return sprintf('<meta name="sentry-trace" content="%s"/>', getTraceparent());
196+
return sprintf('<meta name="sentry-trace" content="%s"/>', self::escapeMetaTagContent(getTraceparent()));
197197
}
198198

199199
/**
@@ -215,7 +215,12 @@ public static function sentryW3CTracingMeta(): string
215215
*/
216216
public static function sentryBaggageMeta(): string
217217
{
218-
return sprintf('<meta name="baggage" content="%s"/>', getBaggage());
218+
return sprintf('<meta name="baggage" content="%s"/>', self::escapeMetaTagContent(getBaggage()));
219+
}
220+
221+
private static function escapeMetaTagContent(string $value): string
222+
{
223+
return htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
219224
}
220225

221226
/**
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?php
2+
3+
namespace Sentry\Laravel\Tests;
4+
5+
use Mockery;
6+
use Sentry\Laravel\Integration;
7+
use Sentry\State\Scope;
8+
use Sentry\Tracing\Span;
9+
10+
class IntegrationMetaTagTest extends TestCase
11+
{
12+
private const DANGEROUS_PAYLOAD = '</meta><script>alert("owned")</script>';
13+
14+
protected function tearDown(): void
15+
{
16+
\Sentry\configureScope(static function (Scope $scope): void {
17+
$scope->setSpan(null);
18+
});
19+
20+
parent::tearDown();
21+
}
22+
23+
public function testSentryTracingMetaEscapesDangerousTraceparentContent(): void
24+
{
25+
$this->resetApplicationWithConfig([
26+
'sentry.traces_sample_rate' => 1.0,
27+
]);
28+
29+
$dangerousTraceparent = self::DANGEROUS_PAYLOAD;
30+
31+
$this->setDangerousSpanValues($dangerousTraceparent, 'safe-baggage');
32+
33+
$metaTag = Integration::sentryTracingMeta();
34+
$expected = sprintf(
35+
'<meta name="sentry-trace" content="%s"/>',
36+
htmlspecialchars($dangerousTraceparent, ENT_QUOTES, 'UTF-8')
37+
);
38+
39+
$this->assertSame($expected, $metaTag);
40+
$this->assertStringContainsString('&lt;script&gt;', $metaTag);
41+
$this->assertStringNotContainsString('<script>', $metaTag);
42+
}
43+
44+
public function testSentryBaggageMetaEscapesDangerousBaggageContent(): void
45+
{
46+
$this->resetApplicationWithConfig([
47+
'sentry.traces_sample_rate' => 1.0,
48+
]);
49+
50+
$dangerousBaggage = self::DANGEROUS_PAYLOAD;
51+
52+
$this->setDangerousSpanValues('safe-traceparent', $dangerousBaggage);
53+
54+
$metaTag = Integration::sentryBaggageMeta();
55+
$expected = sprintf(
56+
'<meta name="baggage" content="%s"/>',
57+
htmlspecialchars($dangerousBaggage, ENT_QUOTES, 'UTF-8')
58+
);
59+
60+
$this->assertSame($expected, $metaTag);
61+
$this->assertStringContainsString('&lt;script&gt;', $metaTag);
62+
$this->assertStringNotContainsString('<script>', $metaTag);
63+
}
64+
65+
public function testSentryTracingMetaReturnsAWellFormedMetaTag(): void
66+
{
67+
$meta = Integration::sentryTracingMeta();
68+
69+
$this->assertStringStartsWith('<meta name="sentry-trace" content="', $meta);
70+
$this->assertStringEndsWith('"/>', $meta);
71+
}
72+
73+
public function testSentryBaggageMetaReturnsAWellFormedMetaTag(): void
74+
{
75+
$meta = Integration::sentryBaggageMeta();
76+
77+
$this->assertStringStartsWith('<meta name="baggage" content="', $meta);
78+
$this->assertStringEndsWith('"/>', $meta);
79+
}
80+
81+
private function setDangerousSpanValues(string $traceparent, string $baggage): void
82+
{
83+
$span = Mockery::mock(Span::class);
84+
$span->shouldReceive('toTraceparent')->andReturn($traceparent)->zeroOrMoreTimes();
85+
$span->shouldReceive('toBaggage')->andReturn($baggage)->zeroOrMoreTimes();
86+
87+
\Sentry\configureScope(static function (Scope $scope) use ($span): void {
88+
$scope->setSpan($span);
89+
});
90+
}
91+
}

0 commit comments

Comments
 (0)