With the astronomical rise of vibe coding and non-technical folks shipping software, it’s become apparent that now more than ever, we
need to be aware of very insecure software flooding the market.
One of the mistakes I’m seeing now and again is developers exposing too much data (than what’s required in the
frontend).
There’s no excuse for having a record’s updated_at, deleted_at and created_at fields in your API responses if the
frontend doesn’t need them.

Response from a blogging platform’s API showing unnecessary fields exposed
This is unfortunately a very common mistake that more often than not leads to security vulnerabilities and performance issues.
APIs are doorways to the data you’re storing and ultimately to your client’s business as well. They are a very detailed description of the
client’s business processes, as well.
How does business xyz handle my data when I sign up? How do they process payments? How do they handle refunds?
For example, by looking at a certain fintech startup’s API responses, I was able to map at the different processes and
verifications they have in place while handling a payment.
Take an instance of the image above (it is from a blogging platform’s API). The API response contains data in this
format:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| {
"id": 7,
"title": "Sleep Your Way To The Top: How, Why And With Who",
"content":"...full article content...",
"slug": "sleep-your-way-to-the-top-how-why-and-with-who",
"excerpt": "These are the confessions of a young executive who thought he was on the fast track to the top. Kumbe… ",
"type": "feature",
"status": "draft",
"isPremium": false,
"isFeatured": true,
"publishedAt": null,
"createdAt": "2025-07-18T10:30:19.641Z",
"updatedAt": "2025-08-19T15:13:45.906Z",
"authorId": 17,
"categoryId": 1,
"columnType": null,
"tags": {},
"author": {
"id": 17,
"slug": "tom-rwahwire",
"user": {
"id": 32,
"fullName": "Tom Rwahwire",
"username": "tom_rwahwire"
}
}
}
|
Suppose I’m a malicious user and I want to read a premium article without paying for it. What could I do?
I could get my authentication token, then try sending a PATCH request to the articles endpoint changing the isPremium field to
true. I could keep doing this for all premium articles that I want to read.
We certainly don’t need to expose some fields for example createdAt, updatedAt, authorId, categoryId, etc. if
they are not being used in the frontend.
How do we achieve this?
We can reduce the fields to the absolute minimum required by the frontend. For example:
1
2
3
4
5
6
7
8
9
| {
"title": "Sleep Your Way To The Top: How, Why And With Who",
"slug": "sleep-your-way-to-the-top-how-why-and-with-who",
"excerpt": "These are the confessions of a young executive who thought he was on the fast track to the top. Kumbe… ",
"type": "feature",
"isPremium": false,
"isFeatured": true,
"publishedAt": null,
}
|
This can be achieved by preparing response structures or using serialization libraries that allow you to define which
fields to include or exclude in the API responses.
For example in Go, you can declare response structs that only include the necessary fields:
1
2
3
4
5
6
7
8
9
10
| type ArticleResponse struct {
ID int `json:"id"`
Title string `json:"title"`
Slug string `json:"slug"`
Excerpt string `json:"excerpt"`
Type string `json:"type"`
IsPremium bool `json:"isPremium"`
IsFeatured bool `json:"isFeatured"`
PublishedAt *time.Time `json:"publishedAt,omitempty"`
}
|
Then map your data models to these response structs before sending them to the frontend.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
| // Article represents the full article model from the database
type Article struct {
ID int
Title string
Slug string
Excerpt string
Type string
IsPremium bool
IsFeatured bool
PublishedAt *time.Time
CreatedAt time.Time
UpdatedAt time.Time
AuthorID int
CategoryID int
}
// Assuming this is the an Article response from your database
article := Article{
ID: 7,
Title: "Sleep Your Way To The Top: How, Why And With Who",
Slug: "sleep-your-way-to-the-top-how-why-and-with-who",
Excerpt: "These are the confessions of a young executive who thought he was on the fast track to the top. Kumbe… ",
Type: "feature",
IsPremium: false,
IsFeatured: true,
PublishedAt: nil,
CreatedAt: time.Date(2025, 7, 18, 10, 30, 19, 641000000, time.UTC),
UpdatedAt: time.Date(2025, 8, 19, 15, 13, 45, 906000000, time.UTC),
AuthorID: 17,
CategoryID: 1,
}
// Set content type headers and marshal the response and then,
func GetArticleResponse(article Article) ArticleResponse {
return ArticleResponse{
Title: article.Title,
Slug: article.Slug,
Excerpt: article.Excerpt,
Type: article.Type,
IsPremium: article.IsPremium,
IsFeatured: article.IsFeatured,
PublishedAt: article.PublishedAt,
}
}
|
This way, we can be sure that only the necessary data is sent to the frontend, reducing the risk of exposing sensitive
information.
In any case, you have a software project that you would like us to discuss, reach out via hello@terraconsults.co
Resources