Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions packages/prime-tunnel/src/prime_tunnel/models.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from datetime import datetime
from typing import List, Optional

from pydantic import BaseModel, Field
from pydantic import BaseModel, Field, SecretStr


class TunnelInfo(BaseModel):
Expand All @@ -11,16 +11,16 @@ class TunnelInfo(BaseModel):
name: Optional[str] = Field(None, description="Friendly name")
hostname: str = Field(..., description="Tunnel hostname")
url: str = Field(..., description="Full HTTPS URL")
frp_token: str = Field(..., description="Authentication token for frpc")
binding_secret: str = Field("", description="Per-tunnel secret for frpc metadata")
frp_token: SecretStr = Field(..., description="Authentication token for frpc")
binding_secret: SecretStr = Field(default=SecretStr(""), description="Per-tunnel secret for frpc metadata")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

SecretStr masked in frpc config

High Severity

TunnelInfo now types frp_token and binding_secret as SecretStr, but _write_frpc_config still embeds them in f-strings. Pydantic masks SecretStr in string conversion, so the generated frpc config gets placeholder values instead of the real token and binding secret, and the client cannot authenticate to frps.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 01fa645. Configure here.

Comment on lines +14 to +15

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Unmask frpc credentials before writing config

With these fields now typed as SecretStr, f-stringing self._tunnel_info.frp_token and binding_secret in Tunnel._write_frpc_config() no longer inserts the backend values; SecretStr renders as masked text. Every Tunnel.start() will write masked credentials such as auth.token = "**********" into the frpc config, so frpc authenticates with the wrong token and new tunnels fail to connect. The config path needs to use get_secret_value() or another explicit unwrapping step before formatting.

Useful? React with 👍 / 👎.

server_host: str = Field(..., description="frps server hostname")
server_port: int = Field(7000, description="frps server port")
local_port: Optional[int] = Field(None, description="Local port forwarded by the tunnel")
labels: List[str] = Field(default_factory=list, description="Tunnel labels")
http_user: Optional[str] = Field(
None, description="HTTP basic auth username, if auth is enabled"
)
http_password: Optional[str] = Field(
http_password: Optional[SecretStr] = Field(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

http_password returns SecretStr not str

Medium Severity

The Tunnel.http_password property is annotated as Optional[str] but forwards TunnelInfo.http_password, which is now Optional[SecretStr]. Callers that expect a plain string for HTTP basic auth or logging get a SecretStr instance instead of the password text unless they call get_secret_value() themselves.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 01fa645. Configure here.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Return the generated basic auth password unmasked

When http_user is set, the backend returns http_password only in the create response and the CLI prints tunnel.http_password to the user. After changing this field to SecretStr, that property returns a secret object whose string representation is masked, so the CLI displays ********** and the user never receives the password needed to access the tunnel. Keep the model secret internally but expose get_secret_value() through the property or CLI.

Useful? React with 👍 / 👎.

None,
description=(
"Auto-generated HTTP basic auth password. Only present in the "
Expand Down