Skip to content

Residual: whitespace `InferenceUrl` overwrites a live one #2032

Open @a-kuprin opened 2026-10-15 18:01 UTC 1 comment Updated 2026-10-15 20:40 UTC
enhancement

Residual: whitespace InferenceUrl overwrites a live one

Raised with https://github.com/gonka-ai/gonka/pull/1792#discussion_r4277929808. The host and gateway now open a session when one participant's URL is blank or the lookup fails, so this no longer refuses Chat. It still deletes the address the rest of the network dials.

A followup to the PR https://github.com/gonka-ai/gonka/pull/2031

What is wrong

An update with an empty URL is supposed to leave the stored address alone. TestMsgServer_SubmitNewParticipant_EmptyValuesNoEffect locks that in: Url: "" keeps http://url.

ValidateBasic treats a whitespace-only URL the same way it treats "not provided". The SSRF check runs only when strings.TrimSpace(msg.Url) != "":

```27:31:inference-chain/x/inference/types/message_submit_new_participant.go if strings.TrimSpace(msg.Url) != "" { if err := utils.ValidateURLWithSSRFProtection("url", msg.Url); err != nil { return err } }

The handler then stores `msg.Url` whenever it is not exactly `""`:

```20:22:inference-chain/x/inference/keeper/msg_server_submit_new_participant.go
        if msg.Url != "" {
            existing.InferenceUrl = msg.Url
        }

" " passes validation and replaces a live InferenceUrl. The validator-key field already rejects that shape of value (msg.ValidatorKey != "" && strings.TrimSpace(msg.ValidatorKey) == ""). The URL field lets it through and writes it.

InferenceUrl is the address peers dial for Chat, payload fetch, and peer RPC. After the overwrite that participant has no usable endpoint until they submit a real URL again. They can do that before PoC, so the blank window is temporary and they still look like a normal participant at the boundary. During the window nobody can dial them, and a timeout check against them has no client, so the timeout is accepted without a challenge.

The same message is a footgun. A key rotation that sends a padded URL, meaning "leave the address", silently deletes the registered one.

Change

Trim before the update, and store the URL only when the trimmed value is non-empty. Whitespace then follows the empty-string rule the handler and EmptyValuesNoEffect already describe.

if url := strings.TrimSpace(msg.Url); url != "" {
    existing.InferenceUrl = url
}

Store the trimmed value, so a padded real URL (" http://host ") is not written with the padding. ValidateBasic already accepts it and runs SSRF on the untrimmed string; ValidateURLWithSSRFProtection should keep seeing the original, and only the stored field is trimmed.

Do the same on create, in createNewParticipant: set InferenceUrl from the trimmed URL. A first registration of " " currently stores the spaces.

No migration. Participants already stored with a whitespace URL stay that way until they submit a real one. The devshard side already treats a blank trimmed URL as missing.

Test

Extend TestMsgServer_SubmitNewParticipant_EmptyValuesNoEffect (or add a sibling) with a second update whose Url is " " and whose keys are "". Expect InferenceUrl, ValidatorKey, and WorkerPublicKey unchanged.

Add a create case: Url: " " stores InferenceUrl == "".


💬 Comments (1)

@redstartechno commented 2026-10-15 20:40 UTC

Taking this one: trim msg.Url in the SubmitNewParticipant handler and store it only when the trimmed value is non-empty (update and create paths), with cases added to the existing EmptyValuesNoEffect test. Branch based on upgrade-v0.2.17; PR follows shortly.


🔄 Auto-synced from Issue #2032 every hour.