Safeguard
Application Security•

CWE-766 Critical Data Element Declared Public in Java and C#

A security-relevant field declared public can be read or changed by any code that holds the object. See why private, final and static matter and how to refactor.

Safeguard Security Team
3 min read

CWE-766 fires when a product declares a critical variable, field or member public although the intended security policy requires it to be private.

MITRE lists C++, C# and Java. These are the languages where visibility modifiers carry the enforcement.

How it happens

Public is the lazy default. A field gets exposed during prototyping, other code starts using it, and nobody tightens it later. Then the field holds something that matters, such as a limit, a user name, a home directory or a permission flag.

// Vulnerable: any code with a reference can read or overwrite this
public class Session {
    public String userName;
    public boolean isAdmin;
}

CVE-2010-3860 in the record shows the read side: variables declared public allowed remote read of system properties such as the user name and home directory.

What an attacker gains

MITRE records integrity and confidentiality. Anyone with access to the containing object can alter or read the value. There is a second effect: it reduces maintainability, which makes vulnerabilities harder to find and fix and easier to introduce.

How to find it

Static analysis can find some instances, as the record notes. A fast manual pass works well too: grep for public fields, then ask of each one whether a wrong value could change a security decision.

How to fix it

MITRE's advice is short: data should be private, static and final whenever possible. Early instantiation, blocked access and resistance to tampering follow from that.

// Fix: private, final, read through a method
public class Session {
    private final String userName;
    private final boolean admin;
    public Session(String userName, boolean admin) {
        this.userName = userName;
        this.admin = admin;
    }
    public String userName() { return userName; }
}

Making a field final means no code can reassign it after construction. If a setter is truly needed, see CWE-767 and validate the incoming value.

Public by default is a design smell

Visibility is the cheapest access control a language gives you, and it costs nothing at runtime. Declaring a field public gives up that control for the whole program, and for any code that later links against it.

The security angle is not only direct access. A public field has no place to put validation. A setter can reject a negative number, a role name that does not exist, or a path outside an allowed directory. A raw field accepts whatever it is given, and every caller must remember the rules, which they will not.

MITRE also flags the maintainability cost: when fields are open, any code in the system might depend on them, so changing or protecting one later means auditing every use. That makes vulnerabilities slower to find and fix.

A sensible rule for reviews is to start from private and final, and widen access only with a written reason. For fields that carry identity, permission or limit values, widening should need a second reviewer.

Quick check

What does final add beyond private?

Private limits who can reach the field. Final also stops anyone, including your own code, from reassigning it after construction.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.