Skip to content

fix(TaskProcessing): Harden task scheduling with webhooks - #63687

Open
marcelklehr wants to merge 1 commit into
masterfrom
fix/harden-task-processing-webhook
Open

fix(TaskProcessing): Harden task scheduling with webhooks#63687
marcelklehr wants to merge 1 commit into
masterfrom
fix/harden-task-processing-webhook

Conversation

@marcelklehr

Copy link
Copy Markdown
Member

Checklist

AI (if applicable)

  • The content of this PR was partly or fully generated using AI

Signed-off-by: Marcel Klehr <mklehr@gmx.net>
@marcelklehr marcelklehr added this to the Nextcloud 36 milestone Aug 27, 2026
@marcelklehr
marcelklehr requested a review from a team as a code owner August 27, 2026 08:30
@marcelklehr marcelklehr added the 3. to review Waiting for reviews label Aug 27, 2026
@marcelklehr
marcelklehr requested review from CarlSchwan, icewind1991 and leftybournes and removed request for a team August 27, 2026 08:30
@marcelklehr
marcelklehr requested a review from come-nc August 27, 2026 08:30
@marcelklehr

Copy link
Copy Markdown
Member Author

/backport to stable32

@marcelklehr

Copy link
Copy Markdown
Member Author

/backport to stable33

@marcelklehr

Copy link
Copy Markdown
Member Author

/backport to stable34

@marcelklehr

Copy link
Copy Markdown
Member Author

/backport to stable35

@@ -168,6 +169,18 @@ private function handleScheduleTaskInternal(
bool $preferStreaming = false,
): DataResponse {
$task = new Task($type, $input, $appId, $this->userId, $customId);
if ($webhookUri !== null && $webhookUri !== ''
&& str_starts_with((string)$webhookMethod, 'HTTP:')) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also check when the method is lowercase? I mean, are we sure the method is systematically uppercase?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@julien-nc
julien-nc self-requested a review August 27, 2026 09:28
@marcelklehr
marcelklehr requested a review from kesselb August 27, 2026 09:46

@joshtrichards joshtrichards left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this validation be moved into the manager to also cover callers that schedule tasks directly? e.g., could a shared validator be invoked from prepareTask() to cover all scenarios / both scheduleTask() and runTask()?

@@ -168,6 +169,18 @@ private function handleScheduleTaskInternal(
bool $preferStreaming = false,
): DataResponse {
$task = new Task($type, $input, $appId, $this->userId, $customId);
if ($webhookUri !== null && $webhookUri !== ''

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a dedicated validator or shared constants/helper would keep scheduling and execution behavior aligned (i.e. with Manager::runWebhook()?

if (!is_string($host) || $host === ''
|| !in_array($scheme, ['http', 'https'], true)
|| !$this->remoteHostValidator->isValid($host)) {
return new DataResponse(['message' => 'Bad webhook URI'],

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return new DataResponse(['message' => 'Bad webhook URI'],
return new DataResponse(['message' => 'Invalid webhook URI, remote host, or method.'],

@@ -168,6 +169,18 @@ private function handleScheduleTaskInternal(
bool $preferStreaming = false,
): DataResponse {
$task = new Task($type, $input, $appId, $this->userId, $customId);
if ($webhookUri !== null && $webhookUri !== ''
&& str_starts_with((string)$webhookMethod, 'HTTP:')) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this mean validation is bypassed entirely for anything that doesn't start with HTTP:?

I think the validation needs to be more explicit regarding URI and method combos:

  • Neither supplied: valid non-webhook task
  • Both supplied validate according to HTTP: or AppAPI:.
  • Only one supplied: return error response

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this mean validation is bypassed entirely for anything that doesn't start with HTTP:?

yes, because if the method doesn't start with HTTP, we don't take URLs at all

@joshtrichards joshtrichards linked an issue Aug 27, 2026 that may be closed by this pull request
8 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: SSRF Through webhookURI in TaskProcessing

3 participants