Bug 2547357 (CVE-2026-107151)

Summary: CVE-2026-107151 rubygem-smart_proxy_dynflow: task update and done callbacks accept unauthenticated requests
Product: [Other] Security Response Reporter: OSIDB Bzimport <bzimport>
Component: vulnerabilityAssignee: Product Security <prodsec-ir-bot>
Status: NEW --- QA Contact:
Severity: medium Docs Contact:
Priority: medium    
Version: unspecifiedCC: anthomas, ehelms, ggainey, jpasqual, juwatts, mdellweg, mhulan, nmoumoul, osousa, pcreech, rchan, security-response-team, smallamp, tmalecek
Target Milestone: ---Keywords: Security
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: ---
Doc Text:
Missing authentication has been found in remote-execution task updates in the smart_proxy_dynflow package. The progress and completion callbacks accept a report when the one-time token is missing. A network attacker or user must already know the identifier of a running job. This applies when remote execution is set to pull or pull-mqtt mode. They can send their own job output and mark the job as a success or a failure. The job is then recorded with that result.
Story Points: ---
Clone Of: Environment:
Last Closed: Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description OSIDB Bzimport 2026-10-07 10:20:13 UTC
Proxy::Dynflow::Api selects authorize_with_token from the path alone. If the Authorization header is absent, that method returns false and does not halt. A Sinatra before filter ignores the return value, so POST /dynflow/tasks/<uuid>/update and /done reach dispatch_external_event. A second bypass sits in the same check: OtpManager.authenticate treats a Basic token with no colon as otp = nil, and passwords[username] == nil is true when that task has no stored OTP. generate_otp has no production caller on current smart_proxy_remote_execution_ssh 1.0.x. On 0.11.x it is called only by PollingScriptRunner, and only in async-SSH mode. Omitting the header still bypasses that case.

This does not launch jobs. In the default :ssh mode, Runner::Base#external_event refreshes and drops the payload. In :pull and :'pull-mqtt', PullScript#process_external_event stores the caller’s output and exit_code, and exit code 0 is recorded as success. 

On Satellite 6.16–6.18, async-SSH PollingScriptRunner#external_event can also apply the payload when manual_mode is set. That runner was removed in smart_proxy_remote_execution_ssh 1.0.0 (commit d8d1811, 2025-11-28). 

The attacker must already know a live execution-plan UUID. Step ids are small integers. The console flaw below is what gives those UUIDs to a host that holds a CA-signed certificate.

Likely to be introduced in smart_proxy_dynflow 0.4.0 by commit e205e19.