fix: sanitize error output in server validation logs (#9197)
This commit is contained in:
commit
25dcde6a47
7 changed files with 102 additions and 5 deletions
|
|
@ -30,7 +30,8 @@ public function handle(Server $server)
|
|||
]);
|
||||
['uptime' => $this->uptime, 'error' => $error] = $server->validateConnection();
|
||||
if (! $this->uptime) {
|
||||
$this->error = 'Server is not reachable. Please validate your configuration and connection.<br>Check this <a target="_blank" class="text-black underline dark:text-white" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help. <br><br><div class="text-error">Error: '.$error.'</div>';
|
||||
$sanitizedError = htmlspecialchars($error ?? '', ENT_QUOTES, 'UTF-8');
|
||||
$this->error = 'Server is not reachable. Please validate your configuration and connection.<br>Check this <a target="_blank" class="text-black underline dark:text-white" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help. <br><br><div class="text-error">Error: '.$sanitizedError.'</div>';
|
||||
$server->update([
|
||||
'validation_logs' => $this->error,
|
||||
]);
|
||||
|
|
|
|||
|
|
@ -45,7 +45,8 @@ public function handle(): void
|
|||
// Validate connection
|
||||
['uptime' => $uptime, 'error' => $error] = $this->server->validateConnection();
|
||||
if (! $uptime) {
|
||||
$errorMessage = 'Server is not reachable. Please validate your configuration and connection.<br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help. <br><br>Error: '.$error;
|
||||
$sanitizedError = htmlspecialchars($error ?? '', ENT_QUOTES, 'UTF-8');
|
||||
$errorMessage = 'Server is not reachable. Please validate your configuration and connection.<br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help. <br><br>Error: '.$sanitizedError;
|
||||
$this->server->update([
|
||||
'validation_logs' => $errorMessage,
|
||||
'is_validating' => false,
|
||||
|
|
@ -197,7 +198,7 @@ public function handle(): void
|
|||
]);
|
||||
|
||||
$this->server->update([
|
||||
'validation_logs' => 'An error occurred during validation: '.$e->getMessage(),
|
||||
'validation_logs' => 'An error occurred during validation: '.htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8'),
|
||||
'is_validating' => false,
|
||||
]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,7 +63,8 @@ public function checkConnection()
|
|||
$this->dispatch('success', 'Server is reachable.');
|
||||
$this->dispatch('refreshServerShow');
|
||||
} else {
|
||||
$this->dispatch('error', 'Server is not reachable.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help.<br><br>Error: '.$error);
|
||||
$sanitizedError = htmlspecialchars($error ?? '', ENT_QUOTES, 'UTF-8');
|
||||
$this->dispatch('error', 'Server is not reachable.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help.<br><br>Error: '.$sanitizedError);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,7 +89,8 @@ public function validateConnection()
|
|||
$this->authorize('update', $this->server);
|
||||
['uptime' => $this->uptime, 'error' => $error] = $this->server->validateConnection();
|
||||
if (! $this->uptime) {
|
||||
$this->error = 'Server is not reachable. Please validate your configuration and connection.<br>Check this <a target="_blank" class="text-black underline dark:text-white" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help. <br><br><div class="text-error">Error: '.$error.'</div>';
|
||||
$sanitizedError = htmlspecialchars($error ?? '', ENT_QUOTES, 'UTF-8');
|
||||
$this->error = 'Server is not reachable. Please validate your configuration and connection.<br>Check this <a target="_blank" class="text-black underline dark:text-white" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help. <br><br><div class="text-error">Error: '.$sanitizedError.'</div>';
|
||||
$this->server->update([
|
||||
'validation_logs' => $this->error,
|
||||
]);
|
||||
|
|
|
|||
|
|
@ -269,6 +269,13 @@ public static function flushIdentityMap(): void
|
|||
|
||||
use HasSafeStringAttribute;
|
||||
|
||||
public function setValidationLogsAttribute($value): void
|
||||
{
|
||||
$this->attributes['validation_logs'] = $value !== null
|
||||
? \Stevebauman\Purify\Facades\Purify::config('validation_logs')->clean($value)
|
||||
: null;
|
||||
}
|
||||
|
||||
public function type()
|
||||
{
|
||||
return 'server';
|
||||
|
|
|
|||
|
|
@ -49,6 +49,17 @@
|
|||
'AutoFormat.RemoveEmpty' => false,
|
||||
],
|
||||
|
||||
'validation_logs' => [
|
||||
'Core.Encoding' => 'utf-8',
|
||||
'HTML.Doctype' => 'HTML 4.01 Transitional',
|
||||
'HTML.Allowed' => 'a[href|title|target|class],br,div[class],pre[class],span[class],p[class]',
|
||||
'HTML.ForbiddenElements' => '',
|
||||
'CSS.AllowedProperties' => '',
|
||||
'AutoFormat.AutoParagraph' => false,
|
||||
'AutoFormat.RemoveEmpty' => false,
|
||||
'Attr.AllowedFrameTargets' => ['_blank'],
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|
|
|
|||
75
tests/Feature/ServerValidationXssTest.php
Normal file
75
tests/Feature/ServerValidationXssTest.php
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
use App\Models\Server;
|
||||
use App\Models\Team;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
beforeEach(function () {
|
||||
$user = User::factory()->create();
|
||||
$this->team = Team::factory()->create();
|
||||
$user->teams()->attach($this->team);
|
||||
$this->actingAs($user);
|
||||
session(['currentTeam' => $this->team]);
|
||||
|
||||
$this->server = Server::factory()->create([
|
||||
'team_id' => $this->team->id,
|
||||
]);
|
||||
});
|
||||
|
||||
it('strips dangerous HTML from validation_logs via mutator', function () {
|
||||
$xssPayload = '<img src=x onerror=alert(document.domain)>';
|
||||
$this->server->update(['validation_logs' => $xssPayload]);
|
||||
$this->server->refresh();
|
||||
|
||||
expect($this->server->validation_logs)->not->toContain('<img')
|
||||
->and($this->server->validation_logs)->not->toContain('onerror');
|
||||
});
|
||||
|
||||
it('strips script tags from validation_logs', function () {
|
||||
$xssPayload = '<script>alert("xss")</script>';
|
||||
$this->server->update(['validation_logs' => $xssPayload]);
|
||||
$this->server->refresh();
|
||||
|
||||
expect($this->server->validation_logs)->not->toContain('<script');
|
||||
});
|
||||
|
||||
it('preserves allowed HTML in validation_logs', function () {
|
||||
$allowedHtml = 'Server is not reachable.<br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs">documentation</a> for further help.<br><br><div class="text-error">Error: Connection refused</div>';
|
||||
$this->server->update(['validation_logs' => $allowedHtml]);
|
||||
$this->server->refresh();
|
||||
|
||||
expect($this->server->validation_logs)->toContain('<a')
|
||||
->and($this->server->validation_logs)->toContain('<br')
|
||||
->and($this->server->validation_logs)->toContain('<div')
|
||||
->and($this->server->validation_logs)->toContain('Connection refused');
|
||||
});
|
||||
|
||||
it('allows null validation_logs', function () {
|
||||
$this->server->update(['validation_logs' => null]);
|
||||
$this->server->refresh();
|
||||
|
||||
expect($this->server->validation_logs)->toBeNull();
|
||||
});
|
||||
|
||||
it('sanitizes XSS embedded within valid error HTML', function () {
|
||||
$maliciousError = 'Server is not reachable.<br><div class="text-error">Error: <img src=x onerror=alert(document.cookie)></div>';
|
||||
$this->server->update(['validation_logs' => $maliciousError]);
|
||||
$this->server->refresh();
|
||||
|
||||
expect($this->server->validation_logs)->toContain('<div')
|
||||
->and($this->server->validation_logs)->toContain('Error:')
|
||||
->and($this->server->validation_logs)->not->toContain('onerror')
|
||||
->and($this->server->validation_logs)->not->toContain('<img');
|
||||
});
|
||||
|
||||
it('sanitizes event handler attributes in validation_logs', function () {
|
||||
$payload = '<div onmouseover="alert(1)" class="text-error">Error</div>';
|
||||
$this->server->update(['validation_logs' => $payload]);
|
||||
$this->server->refresh();
|
||||
|
||||
expect($this->server->validation_logs)->toContain('<div')
|
||||
->and($this->server->validation_logs)->not->toContain('onmouseover');
|
||||
});
|
||||
Loading…
Reference in a new issue