← All Field Notes
GHL · Digital Marketing Agency · Sep 17, 2026

We Set The Password Correctly, And The Correct Password Stopped Working

Key takeaways

On August 12 we built a one page link library for our sales team. Every deck, demo site and booking link worth sending a prospect, on one page, with a copy button next to each. It is internal, so it sits behind a short access code.

The site runs on Cloudflare Pages, a static host with small functions that run in front of the pages. One of those functions is the gate. It compares what you type against a secret stored on the hosting project, and lets you in if they match.

We tested it locally. It worked. We deployed it. It worked. Then we did the responsible thing and set the real code as a proper secret on the project, instead of relying on the default written into the function. From that moment on, the correct code was refused.

The same error for right and wrong

The first thing you do when a password fails is type it again, slowly. Same result. Then you type something deliberately wrong, to see if the error changes. It did not. The right code and a wrong code both got the same unauthorized response, and nothing in the logs told them apart.

That is what makes this bug expensive. Every signal says the value is wrong. You check the value, and the value is right.

The value we had set was not quite the value we meant. We had piped it into the hosting tool's secret command from PowerShell. When PowerShell pipes a string into a native program, it adds a line ending to the end. The tool takes whatever arrives and stores it as is. So the stored secret was the code plus an invisible carriage return and newline. The deploy succeeded, the secret showed as present, and no warning appeared anywhere.

The code typed into the shell reaches the host with two invisible characters added, so the stored secret is two characters longer than the code a person types and every comparison fails

It also explains the strangest part, which is that it worked before we set it. Local testing and the first deploy had no secret at all, so the function fell back to its default, and the default had no line ending. The symptom read as "setting the secret correctly broke the gate". That sentence makes no sense until you know about the invisible characters.

The fix that day was one line in the function: trim the secret when it is read, and trim what the person typed. Whitespace at either end stops mattering.

It came back wearing a different error

On August 25 it happened again, on a different tool, with higher stakes. This time the secret was an access token for our CRM, stored on another project so that project's functions could call the CRM on our behalf.

We had learned the lesson, or thought we had. The token was written to a file carefully, with no trailing newline, and then piped from that file into the secret command. PowerShell added the line ending anyway, because it adds one on the pipe, not in the file.

The deploy succeeded. The secret list showed the token was there. Every call to the CRM came back unauthorized with a message saying the token was invalid.

That message sends you in exactly the wrong direction. It reads like a revoked or expired token, so you go and check the token. The token was fine. We lost about an hour before looking at what was actually being sent. The token was going out inside the authorization header with a newline on the end, and the CRM, reasonably, refused it.

What we changed so it cannot happen a third way

Two changes, and they cover different people.

The first protects against whoever sets the secret next. Our functions trim a secret when they read it. It does not matter how carefully this secret was written today. Somebody will rotate it in six months, from a different shell, and write it a different way. Code that trims cannot be broken by that.

The second protects against us. Our deploy script no longer pipes secrets into the hosting tool at all. It reads the value from a local settings file, trims it, and sends it straight to the host's own API, which stores exactly the bytes it receives. The value never appears on a command line. And when it finishes, it prints the number of characters it stored, which is the one number that would have saved that hour.

Two protections side by side: every function trims a secret when it reads it, and the deploy script sets secrets through the host's API and reports how many characters it stored

One more thing that caught us in between: on this host, a new secret does nothing until the next deploy. Set the value, then redeploy, then test. Testing between the first two steps tests the old value.

What this means for your business

You may never paste a secret into a hosting tool. You probably do paste credentials into integration settings, website plugins and automation tools, often copied out of an email or a password manager. A trailing space or a line break comes along for the ride more often than you would think, and most tools will not tell you.

When a connection fails with a key you are sure is correct, do not start by generating a new one. Check the length first. If your key is supposed to be 40 characters and the field holds 42, you have found the problem without touching the key.

For a Go High Level San Jose business connecting its CRM to other tools, ask whoever does that work one question: do your integrations trim credentials when they read them? A yes means a stray space during a key rotation stays a non event instead of an afternoon of outages.

Want this built for you

We build websites, gated tools and CRM integrations, and we build them to survive the next person who touches the settings. Start at optechsol.llc.

Want this working in your business?
Get my plan ← Back to all Field Notes